The return function is open, closed or closed from the clock.

I have a bunch of hours of work. I want to determine if the store is open, closed or closes in 30,29,28,27 ... minutes. I do this in Xcode / Objectic-C. Now I have to do this to say 50 different hours of work. I made a function that does this, but it is not very efficient and includes many if-else statements. Here is an example of work hours

Monday - Thursday
7:30am - Midnight
Friday
7:30am - 10:00pm
Saturday
9:00am - 10:00pm 
Sunday
9:00am - Midnight 

And here is my function and how I handle it

-(BOOL) dateAndTime:(NSDate*)date getStartDay:(NSInteger)startDay getStartHour:(NSInteger)startHour getStartMin:(NSInteger)startMin getEndDay:(NSInteger)endDay getEndHour:(NSInteger)endHour getEndMin:(NSInteger)endMin{

    NSCalendar *calendar = [NSCalendar currentCalendar];


    const NSCalendarUnit units = NSWeekdayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit;
    NSDateComponents *comps = [calendar components:units fromDate:date];

    if (comps.weekday == 1) {
        comps.weekday = 7;
    }
    else comps.weekday = comps.weekday - 2;

    NSDate *startOfToday;
    [[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&startOfToday interval:NULL forDate:date];

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    NSTimeZone *timeZone = [NSTimeZone localTimeZone];
    [dateFormatter setDateFormat:@"HH:mm"];
    [dateFormatter setTimeZone:timeZone];


    NSString *dateString = [dateFormatter stringFromDate:date];

    NSDate *startDate = [dateFormatter dateFromString:[NSString stringWithFormat:@"%ld:%ld", (long)startHour, (long)startMin]];
    NSDate *endDate = [dateFormatter dateFromString:[NSString stringWithFormat:@"%ld:%ld", (long)endHour, (long)endMin]];

    NSString *startDateString = [dateFormatter stringFromDate:startDate];
    NSString *endDateString = [dateFormatter stringFromDate:endDate];


    if ([startDateString compare:dateString] == NSOrderedAscending && [dateString compare:endDateString] == NSOrderedAscending && startDay <= comps.weekday && comps.weekday <= endDay) {
        return YES;
    }
    else return NO;

}

Now I go through the day, from 0-6 (0 to Monday), and then the time is in 24-hour time. And then use it like this:

    if ([self dateAndTime:date getStartDay:0 getStartHour:7 getStartMin:30 getEndDay:3 getEndHour:23 getEndMin:30] == YES)
        text = @"Open";

    else if ([self dateAndTime:date getStartDay:0 getStartHour:23 getStartMin:30 getEndDay:3 getEndHour:24 getEndMin:0] == YES)
        text = [NSString stringWithFormat:@"Closes in %@ min", countdownNumber];
else text = @"Closed";

, , if, . 8 if-else ( )

, / , 30 ?

, , - .

if-else , https://gist.github.com/spennyf/b0b18e31c3e9deaa0455

/ :)

.m,

@interface HomeTableViewController () {

    ShopHours WeekSchedule[];
}

@end

, , , .m? , .:)

if, 30 , , ? , /.

:)

+4
3

, C . , ( , ). , .

-, " ". , DST, , "1:30 " " , 1:30 , , DST , 1: 30a". , , , .

" " , , , 60 * 24 * 7 (10 080) . , 0 10 079. , ( "" ). , . . , ( ) ( ). , , , . , . .

, . ( ). , WeekTime :

typedef enum {
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday
} Weekday;

@interface WeekTime : NSObject   
@property (nonatomic, readonly) NSInteger minutesSinceStartOfWeek;

- (instancetype)initWithWeekday:(Weekday)weekday hour:(NSInteger)hour minute:(NSInteger)minute;
@end

, .

. , , . 9p, "" 9p, " 1 ."

@interface WeekTimeRange : NSObject
@property (nonatomic, readonly) WeekTime *start;
@property (nonatomic, readonly) WeekTime *end;

- (instancetype)initWithStart:(WeekTime *)start end:(WeekTime *)end;
- (BOOL)contains:(WeekTime *)time;
@end

, contains: . , , start "", end (, "" ). :

- (BOOL)contains:(WeekTime *)time {
    NSInteger queryMinutes = time.minutesSinceStartOfWeek;
    NSInteger startMinutes = self.start.minutesSinceStartOfWeek;
    NSInteger endMinutes = self.end.minutesSinceStartOfWeek;

    if (startMinutes < endMinutes) {
        return (startMinutes <= queryMinutes &&
                queryMinutes < endMinutes);
    } else {
        return (queryMinutes < endMinutes ||
                queryMinutes >= startMinutes);
    }
}

( , start==end undefined. - , " " " ", , " ". , , "...". start==end be undefined.)

, , :

WeekTimeRange *WTMakeRange(Weekday startDay, NSInteger startHour, NSInteger startMinute,
                           Weekday endDay, NSInteger endHour, NSInteger endMinute) {
    return [[WeekTimeRange alloc]
            initWithStart:[[WeekTime alloc] initWithWeekday:startDay hour:startHour minute:startMinute]
            end:[[WeekTime alloc] initWithWeekday:endDay hour:endHour minute:endMinute]];
}

WeekTimeRange *WTFindOpenRangeIncluding(NSArray *ranges, WeekTime *time) {
    for (WeekTimeRange *range in ranges) {
        if ([range contains:time]) {
            return range;
        }
    }
    return nil;
}

NSString *WTStatus(WeekTimeRange *range, WeekTime *requestedTime) {
    if (range != nil) {
        NSInteger minutesLeft = range.end.minutesSinceStartOfWeek - requestedTime.minutesSinceStartOfWeek;
        if (minutesLeft < 0) {
            minutesLeft += [WeekTime maxMinute];
        }
        if (minutesLeft <= 30) {
            return [NSString stringWithFormat:@"Closing in %ld minutes", (long)minutesLeft];
        } else {
            return @"Open";
        }
    } else {
        return @"Closed";
    }
}

. . , , WeekTime , NSDate.

    NSArray *shopHours = @[WTMakeRange(Monday, 7, 30, Tuesday, 0, 0),
                           WTMakeRange(Tuesday, 7, 30, Wednesday, 0, 0),
                           WTMakeRange(Wednesday, 7, 30, Thursday, 0, 0),
                           WTMakeRange(Thursday, 7, 30, Friday, 0, 0),
                           WTMakeRange(Friday, 7, 30, Friday, 22, 0),
                           WTMakeRange(Saturday, 9, 0, Saturday, 22, 0),
                           WTMakeRange(Sunday, 9, 0, Monday, 2, 0)
                           ];

    WeekTime *mondayElevenPM = [[WeekTime alloc] initWithWeekday:Monday hour:23 minute:00];
    WeekTimeRange *openRange = WTFindOpenRangeIncluding(shopHours, mondayElevenPM);
    NSString *result = WTStatus(openRange, mondayElevenPM);
    NSLog(@"%@", result);

, , , . gist. , . , , "...", . ( , ) .

+3

. : - , , , .

, , , - , . , , , , , , .

, , - , - , ..

? , , , , - , ( ), , 24 60 , , . , , , .

, NSCalendar , NSDate.

, , , , , , :

#define TO_MINUTES(hour, min) (hour * 60 + min)

?

, NSArray, , NSDictionary, / - . - , NSDictionary NSNumber. ( , - !)

C- - , .

C :

typedef struct
{
   NSInteger openTime;
   NSInteger closeTime;
} ShopHours;

, :

ShopHours WeekSchedule[] =
{
   {0, 0}, // index 0 - ignore
   { TO_MINUTES(9, 0),  TO_MINUTES(24, 0) }, // index 1 - Sunday
   { TO_MINUTES(7, 30), TO_MINUTES(24, 0) }, // index 2 - Monday
   ...
   { TO_MINUTES(9, 0),  TO_MINUTES(22, 0) }, // index 7 - Saturday
};

, .

( , 0 - NSDateComponents , 1 , ( C-, NSArray) 0, , do - 1 .)

, NSDate NSDateComponents, , :

NSInteger weekday = comps.weekday;
NSInteger minutes = TO_MINUTES(comps.hour, comps.minute);

weekday WeekSchedule minutes , , . :

if (minutes >= WeekSchedule[weekday].openTime && minutes <= WeekSchedule[weekday].closeTime)
{
    // shop is open...
}
else
{
    // shop is closed...
}

, , :

- (NSString *) shopState:(NSDate *)dateAndTime
{
   // break out the weekday, hours and minutes...
   // your code from the question

   NSInteger weekday = comps.weekday;
   NSInteger minutes = TO_MINUTES(comps.hour, comps.minute);

   if (minutes >= WeekSchedule[weekday].openTime && minutes <= WeekSchedule[weekday].closeTime)
   {
      // shop is open...
      // determine if its closing within 30 mins and return an appropriate string
   }
   else
   {
      // shop is closed...
      return @"Closed";
   }
}

, , .

-

, , , - , . , , , :

  • : , .. / , . , .

  • : (1), ...

  • . , / . , , , , , , .

  • : , . DST . , , / - , , . NSCalendar / , /. , , 2 , DST 2 1 , 1:30? , , , ? .

, .

, ( , - , ..) -

, , , , .

:

  • , . . TO_MINUTES, , 0000 . , , , - , , , , , ( / ? )

  • (1), , Sat β†’ Sun, 30 .

  • β†’ . , ( ) ( ). , , , , (, TO_MINUTES(7, 24, 0)), , , 00:00, , 30 ( ).

. DST, .. - , . DST NSTimeZone, , ( 1 ), "" "" , , , / .

; -)

, Objective-C , , , .

, - -, , .

- C- - Objective-C ? - , NSRect et al - Objective-C. , , , , , . , /:

// convenience macro
// day 1 = Sunday, ... 7 = Saturday
#define TO_MINUTES(day, hour, min) ((day * 24 + hour) * 60 + min)

#define WEEK_START TO_MINUTES(1, 0, 0)
#define WEEK_FINISH TO_MINUTES(7, 24, 0)

typedef struct
{  NSInteger openTime;
   NSInteger closeTime;
} ShopHours;

// Opening hours
ShopHours WeekSchedule[] =
{  { TO_MINUTES(1, 0, 0),  TO_MINUTES(1, 0, 15) }, // Sat night special, part of Sat 11:30pm - Sun 0:15am
   { TO_MINUTES(1, 9, 0),  TO_MINUTES(1, 24, 0) }, // Sun 9am - Midnight
   { TO_MINUTES(2, 7, 30), TO_MINUTES(2, 24, 0) }, // Mon 7:30am - Midnight
   { TO_MINUTES(3, 7, 30), TO_MINUTES(3, 24, 0) },
   { TO_MINUTES(4, 7, 30), TO_MINUTES(5, 2, 0)  }, // Midweek madness, Wed 7:30am - Thursday 2am
   { TO_MINUTES(5, 7, 30), TO_MINUTES(5, 24, 0) },
   { TO_MINUTES(6, 7, 30), TO_MINUTES(6, 22, 0) }, // Fri 7:30am - 10pm
   { TO_MINUTES(7, 9, 0),  TO_MINUTES(7, 22, 0) }, // Sat 9am - 10pm
   { TO_MINUTES(7, 23, 30),TO_MINUTES(7, 24, 0) }, // Sat night special, part of Sat 11:30pm - Sun 0:15am
};

- (NSString *) shopState:(NSDate *)dateAndTime
{  NSCalendar *calendar = [NSCalendar currentCalendar];

   const NSCalendarUnit units = NSWeekdayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit;
   NSDateComponents *comps = [calendar components:units fromDate:dateAndTime];

   NSInteger minutes = TO_MINUTES(comps.weekday, comps.hour, comps.minute);
   NSLog(@"%ld (%ld, %ld, %ld)", minutes, comps.weekday, comps.hour, comps.minute);

   unsigned periods = sizeof(WeekSchedule)/sizeof(ShopHours);
   for (unsigned ix = 0; ix < periods; ix++)
   {  if (minutes >= WeekSchedule[ix].openTime)
      {  if (minutes < WeekSchedule[ix].closeTime)
         {
            // shop is open, how long till close time?
            NSInteger closeTime = WeekSchedule[ix].closeTime;
            // handle Sat -> Sun wraparound
            if (closeTime == WEEK_FINISH && WeekSchedule[0].openTime == WEEK_START)
               closeTime += WeekSchedule[0].closeTime - WEEK_START;
            NSInteger closingIn = closeTime - minutes;

            if (closingIn <= 30)
               return [NSString stringWithFormat:@"Closes in %ld min", closingIn];
            else
               return @"Open";
         }
      }
      else // minutes < WeekSchedule[ix].openTime
         break;
   }
   return @"Closed";
}

DST

, , , , , , .

, NSDate , Rob .

NSDate , , NSDateComponents. , 2am 1am - DST, 1:30 . NSDate 1 , , 10 , components:fromDate: 2, , : 00:50, 01:00, 01:10,..., 01:50, 01:00, 01:10,..., 01:50, 02:00, 02:10. 30 , 01:30, 30 , !

, NSDate, // , . ( ) , , , .

+7

, dateAndTime , , , :

@interface MyDateModelObject : NSObject
@property (nonatomic, strong) NSDate *startDay;
@property (nonatomic, assign) NSInteger startHour;
And so on...

dateAndTime :

- (BOOL)dateAndTime:(MyDateModelObject *)myDateModelObject

dateAndTime . . Single Responsibility Principle, , NSDateFormatter, .

dateAndTime gist:

- (NSString *)retrieveStoreState:(MyDateModelObject *)date

Now in your code you can create a model object and set its properties, pass it to retrieveStoreState and force it to return only the state based on the logic you have in the base.

Hope this will give you a good direction. If you follow SRP, you can clear your code and pull up your entity a bit, making it more readable.

+1
source

Source: https://habr.com/ru/post/1568846/


All Articles