Open Hours in Objective-C - Time between two times NSDate - ios

I am trying to perform a segue in Objective-C (XCode) for iOS devices, when the time right now is between two other fixed times. Just like "Open Hours" for stores - when the time right now is between open and close hour.
Here is the code I have been working on - some of the code may look familiar, because I found some useful stuff on SO which helped me - but still I can't get it to work. It doesn't perform the segue when the time passes startTime. It should be in the specified time interval.
The time is in 24-hour format.
// set start time and end time
NSString *startTimeString = #"23:00";
NSString *endTimeString = #"05:00";
// set date formatter 24-hour format
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"HH:mm"];
// german timezone
NSLocale *locale = [[NSLocale alloc]initWithLocaleIdentifier:#"de_DE"];
NSString *nowTimeString = [formatter stringFromDate:[NSDate date]];
// set NSDates for startTime, endTime and nowTime
NSDate *startTime = [formatter dateFromString:startTimeString];
NSDate *endTime = [formatter dateFromString:endTimeString];
NSDate *nowTime = [formatter dateFromString:nowTimeString];
[formatter setLocale:locale];
// compare endTime and startTime with nowTime
NSComparisonResult result1 = [nowTime compare:endTime];
NSComparisonResult result2 = [nowTime compare:startTime];
if ((result1 == NSOrderedDescending) &&
(result2 == NSOrderedAscending)){
NSLog(#"Time is between");
[self performSegueWithIdentifier:#"openHours" sender:self];
} else {
NSLog(#"Time is not between");
}
thanks for taking your time to look at my question. I have been searching and searching, trying and trying, but no luck in making it work yet. Hopefully your answers will help me.

You should little bit change you code
// set NSDates for startTime, endTime and nowTime
int startTime = [self minutesSinceMidnight:[formatter dateFromString:startTimeString]];
int endTime = [self minutesSinceMidnight:[formatter dateFromString:endTimeString]];
int nowTime = [self minutesSinceMidnight:[formatter dateFromString:nowTimeString]];;
[formatter setLocale:locale];
if (nowTime < endTime && nowTime > startTime) {
NSLog(#"Time is between");
} else if (nowTime > endTime && nowTime < startTime) {
NSLog(#"Time is between");
} else {
NSLog(#"Time is not between");
}
And implement method for calculating time:
-(int) minutesSinceMidnight:(NSDate *)date
{
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
unsigned unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit;
NSDateComponents *components = [gregorian components:unitFlags fromDate:date];
return 60 * [components hour] + [components minute];
}

I am interested in an answer that works on ANY date, and not fixed dates for opening and closing.
In that case the simplest approach would be using NSDateComponents. You could store hour, minutes and maybe weekday for opening and closing. to check for now you would break up [NSDate now] into the same NSDateComponents and cop are those.

Related

What is the simple way to detect time is in hours or not?

I am using UIDatePickerView in my project with timeInterval one minute. After selecting time if time is in hours then I have to do some stuff. So how can I detect if user selects time in hours or not?
Try this one , you can get hours between two date.
NSDate* date1 = someDate;
NSDate* date2 = someOtherDate;
NSTimeInterval distanceBetweenDates = [date1 timeIntervalSinceDate:date2];
double secondsInAnHour = 3600;
NSInteger hoursBetweenDates = distanceBetweenDates / secondsInAnHour;
Finally I got answer for my own question
NSDateFormatter *formatter23 = [[NSDateFormatter alloc]init];
[formatter23 setDateFormat:#"yyyy-MM-dd--HH:mm"];
NSDate* date1 = datePicker.date;
[formatter23 setDateFormat:#"mm"];
if ([[formatter23 stringFromDate:date1] isEqualToString:#"00"] || [[formatter23 stringFromDate:date1] isEqualToString:#"30"]){
NSLog(#"Date is in half an hour or hour");
} else{
NSLog(#"Some other");
}
NSDateFormatter *timeFormatter = [[[NSDateFormatter alloc]init]autorelease];
timeFormatter.dateFormat = #"HH";
NSString *date_Hour= [timeFormatter stringFromDate: localDate];
and simple way to get hour only use NSDateComponents class
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSHourCalendarUnit fromDate:[NSDate date]];
NSInteger hour= [components hour];

Check if time of NSDate object has passed

Im trying to check if the time of an NSDate has passed. Ive used the following but that obviously has the year so therefore it has passed. How would I check just the time of the NSDate object, only Hour and minutes are important:
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"HH:mm:ss"];
[dateFormat setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]];
NSDate *date = [dateFormat dateFromString:openingDay.endTime];
if ([date timeIntervalSinceNow] < 0.0) {
}
But the date is:
2000-01-01 5:30:00 p.m. +0000
The time string has the format 'HH:mm:ss'
I tried looking for the answer as I thought it would be common but no luck.
Edit:
I should have elaborated some more, I get a time from a server which is a string. I want to then check if this time is past. The string is an end time of a shops opening hours, I therefore want to check if the shop has closed.
Edit2:
the string I get from the Json object is end_time:17:30:00. I then want to check if the current time is after this time, if so, then show a closed UIAlertView. My approach was to take this string and turn it into a date object and compare it to the current time. However when I convert it to an NSDate object the year is 2000, which is obviously in the past. I hope I have provided enough.
To get the hour and minutes component, you do this:
NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:date];
NSInteger hour = [components hour];
NSInteger minute = [components minute];
You can then create helper methods to keep the code organized:
- (NSInteger)hourFromDate:(NSDate *)date {
return [[NSCalendar currentCalendar] component:(NSCalendarUnitHour) fromDate:date];
}
- (NSInteger)minuteFromDate:(NSDate *)date {
return [[NSCalendar currentCalendar] component:(NSCalendarUnitMinute) fromDate:date];
}
note that component:fromDate:returns directly that component (as NSInteger), since it can only take one component type per parameter, while components:fromDate: returns a NSDateComponents, which then you can grab multiple components.
and then just:
NSDate *endDate = [dateFormat dateFromString:openingDay.endTime];
NSDate *today = [NSDate date];
NSInteger endDateHour = [self hourFromDate:endDate];
NSInteger endDateMinute = [self minuteFromDate:endDate];
NSInteger todayHour = [self hourFromDate:date];
NSInteger todayMinute = [self minuteFromDate:date];
BOOL hasEndMinutePassed = endDateMinute > todayMinute;
BOOL hasEndHourPassed = endDateHour > todayHour;
if ((hasEndHourPassed) || (endDateHour == todayHour && hasEndMinutePassed)) {
//Yep, it passed
} else {
//Nope, it didn't
}
I wrote it like this to keep things organized.
You could also write a category:
Header file:
#interface NSDate (Components)
- (NSInteger)hour;
- (NSInteger)minutes;
#end
Implementation file:
#import "NSDate+Components.h"
#implementation NSDate (Components)
- (NSInteger)hour {
return [[NSCalendar currentCalendar] component:NSCalendarUnitHour fromDate:self];
}
- (NSInteger)minute {
return [[NSCalendar currentCalendar] component:NSCalendarUnitMinute fromDate:self];
}
You can go a bit further than that and add the comparation logic inside the Category itself:
Adding this to the header:
- (BOOL)hourAndMinutesPassedFromDate:(NSDate *)date;
and then the implementation:
- (BOOL)hourAndMinutesPassedFromDate:(NSDate *)date {
BOOL hasEndMinutePassed = [self minute] > [date minute];
BOOL hasEndHourPassed = [self hour] > [date hour];
return ((hasEndHourPassed) || ([self hour] == [date hour] && hasEndMinutePassed));
}
Thats it. I didn't test the logic itself (but it should be accurate, i used something like this before), and of course you are free to modify this to fit your needs.

Getting future date using NSDate and NSTimeInterval

I'm creating a simple timer but am failing to get the resulting date that I'm after.
My problem is that I'm getting -34481.274523 from my NSTimeInterval (nslog at the end) whereas I'm wanting the number of seconds since the current date (currentDate). stopDate is always a date before currentDate.
The code snippet below is called from an nstimer every second. Rather than simply increment an int I'm using a date as it's easier to perform other date related calculations on and format for display.
Here is my code:
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:stopDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"mm:ss"];
NSString *timeString=[dateFormatter stringFromDate:timerDate];
NSLog(#"nstimeinterval: %f", timeInterval);
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components: ( NSHourCalendarUnit | NSYearCalendarUnit) fromDate:timerDate];
NSLog(#"year: %li", (long)components.year);
if (components.year == 2000) {
timeString = #"00:00";
return;
}
NSLog(#"timer: %#", timeString);
timerTicksForCounter = timeString;
NSLog(#"hour: %li", (long)components.hour);
//Used to update uilabel
[self updateTimerLabel];
if (components.year < 2000) {
return;
}
if (components.hour == 0) {
..... I'm doing a bunch of stuff here

How do I accommodate opening and closing dates NSDate comparator on separate days?

Comparing dates is quite complex. I have an app that is comparing opening and closing dates for stores and it works great for times in the same day, i.e. opening a 8am and closing at 5pm the same day.
Here is the code that compares the time:
if ([self timeCompare:openDate until:closeDate withNow:now]) {
NSLog(#"TIMECOMPARATOR = timeCompare>OPEN");
status = YES;
} else {
NSLog(#"TIMECOMPARATOR = timeCompare>CLOSED");
status = NO;
}
return status;
This calls the following method:
+(BOOL)timeCompare:(NSDate*)date1 until:(NSDate*)date2 withNow:(NSDate*)now{
NSLog(#"TIMECOMPARE = open:%# now:%# close:%#", date1, now, date2);
return ([date1 compare:now] == NSOrderedAscending && [date2 compare:now] == NSOrderedDescending);
}
The problem comes when the closing time is "assumed" by a person but of course not by a computer, to close at the next day, such as 7am to 2am. I obviously mean the next day. How do I accommodate for this to signal the computer to be the next day?
Compare the date's unix time. It will be accurate regardless of date as it is constantly increasing.
First you have to convert the strings "7:00 AM", "10:00 PM" to a NSDate from the current day. This can be done e.g. with the following method:
- (NSDate *)todaysDateFromAMPMString:(NSString *)time
{
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
[fmt setLocale:[NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"]];
// Get year-month-day for today:
[fmt setDateFormat:#"yyyy-MM-dd "];
NSString *todayString = [fmt stringFromDate:[NSDate date]];
// Append the given time:
NSString *todaysTime = [todayString stringByAppendingString:time];
// Convert date+time string back to NSDate:
[fmt setDateFormat:#"yyyy-MM-dd h:mma"];
NSDate *date = [fmt dateFromString:todaysTime];
return date;
}
Then you can proceed as in https://stackoverflow.com/a/20441330/1187415:
// Some example values:
NSString *strOpenTime = #"10:00 PM";
NSString *strCloseTime = #"2:00 AM";
NSDate *openTime = [self todaysDateFromAMPMString:strOpenTime];
NSDate *closeTime = [self todaysDateFromAMPMString:strCloseTime];
if ([closeTime compare:openTime] != NSOrderedDescending) {
// closeTime is less than or equal to openTime, so add one day:
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *comp = [[NSDateComponents alloc] init];
[comp setDay:1];
closeTime = [cal dateByAddingComponents:comp toDate:closeTime options:0];
}
NSDate *now = [NSDate date];
if ([now compare:openTime] != NSOrderedAscending &&
[now compare:closeTime] != NSOrderedDescending) {
// Shop is OPEN
} else {
// Shop is CLOSED
}
This is an app design question, not a coding question. You need to define a clear vocabulary for the user to communicate what they mean. I would suggest adding a UISwitch to the screen, with 2 positions on it: "Today" and "Tomorrow". You can add some program logic that takes a guess as to times where you think the user is talking about a date tomorrow, and set the default switch to the "tomorrow" state in that case, but the user should be able to tell you what they mean.
How about you just add a check whether all the three NSDate are having the same date (DDMMYYYY) value?

NSDate past 4pm

Hello I have seen many NSDate comparisons on this site
but they all seems to be very complicated , since I need only to know
if the date now is past 4pm or before 4pm
maybe there is some easy way to achieve this goal ?
[link] (Check if the time and date is between a particular date and time)
but it seems very long and complicated I just need simple bool answer past 4pm or not
- (BOOL)checkTime
{
NSDate* now = [NSDate date];
NSDate *endDate;
[formatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
endDate = [formatter dateFromString:#"2012-12-07 16:00:00"];//well here I have a problem how do I set end day to today 4pm ?
NSLog(#"%d",[now compare:endDate]);
if([now compare:endDate] < 0)
return YES;
else if([now compare:endDate] > 0)
return NO;
else
return NO;
}
EDIT: After the answers I came up with this code
- (BOOL)checkTime
{
NSDate *date = [NSDate date];
NSDateFormatter *df = [NSDateFormatter new];
[df setDateFormat:#"HH"];
int intS =9;
NSInteger HourStart = intS;
NSInteger hour = [[df stringFromDate:date] integerValue];
int hourE = 16;
NSInteger HourEnd = hourE;
if((hour >HourStart) && (hour < HourEnd))
return YES;
else
return NO;
}
For now it is works fine , but I am not sure it will work on another calendars set etc.
In general, I'd prefer to use NSDateComponents and NSCalendar for these sorts of calendrical calculations, since you don't know what calendar the user is using.
Here's a method for doing the comparison in a category on NSDate using date components:
#import <Foundation/Foundation.h>
#interface NSDate (Foo)
- (BOOL)isAfterFourPM;
#end
#implementation NSDate (Foo)
- (BOOL)isAfterFourPM {
unsigned int flags = NSHourCalendarUnit;
NSDateComponents *comps = [[NSCalendar currentCalendar] components:flags fromDate:self];
return (comps.hour >= 16);
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
NSDate *now = [NSDate date];
NSLog(#"is after 4 PM? - %#",([now isAfterFourPM]?#"YES":#"NO"));
// let's try with a different time (17h)
unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
flags |= NSHourCalendarUnit;
NSDateComponents *currentComps = [[NSCalendar currentCalendar] components:flags fromDate:now];
currentComps.hour = 17;
NSDate *afterFourDate = [[NSCalendar currentCalendar] dateFromComponents:currentComps];
NSLog(#"is after 4 PM? - %#",([afterFourDate isAfterFourPM]?#"YES":#"NO"));
}
}
This prints:
2013-12-10 05:16:05.921 Untitled 2[43453:507] is after 4 PM? - NO
2013-12-10 05:16:05.921 Untitled 2[43453:507] is after 4 PM? - YES
(at ~ 5 AM Central time)
In this case, all you need to do, is get the NSHourCalendarUnit component from the date using the current calendar and compare the hour property on NSDateComponents to 16.
The following will give you hour:
NSDate *now = [NSDate date];
NSDateFormatter *df = [NSDateFormatter new];
[df setDateFormat:#"hh"];
NSInteger hour = [[df stringFromDate:now] integerValue];
NOTE:
If you want to check only for 4 then use hh, if for 16 then use HH.
Or in simple words HH for 24 hour format.

Resources