Check if time of NSDate object has passed - ios

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.

Related

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

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.

Match a given day and month in any year in an NSDate?

I’d like to set up an NSDate object which can tell me whether a specified date is between two other dates, but disregard year. I have a little something in my app which does something special at Christmas and I’d like to future-proof it for subsequent years. I’m using the following code to check if the current date is between December 1st and December 31st, but I’ve had to specify the year (2013).
I’m not too sure how to go about modifying it to work for any year – since the dates are converted into plain numeric values, can it even be done?
+ (NSDate *)dateForDay:(NSInteger)day month:(NSInteger)month year:(NSInteger)year
{
NSDateComponents *comps = [NSDateComponents new];
[comps setDay:day];
[comps setMonth:month];
[comps setYear:year];
return [[NSCalendar currentCalendar] dateFromComponents:comps];
}
- (BOOL)laterThan:(NSDate *)date
{
if (self == date) {
return NO;
} else {
return [self compare:date] == NSOrderedDescending;
}
}
- (BOOL)earlierThan:(NSDate *)date
{
if (self == date) {
return NO;
} else {
return [self compare:date] == NSOrderedAscending;
}
}
It sounds like all you need to be able to do is determine if an NSDate falls in December. I believe you can do it like this:
NSDate * now = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *nowComponents = [gregorian components:NSMonthCalendarUnit fromDate:now];
if ([nowComponents month] == 12) {
// It's December, do something
}
If you don't want to be limited to an entire month you could get the month and day components of your current date.
To tell if a date is later in the year than some given date I'd use something like this:
// yearlessDate is in the form MMddHHmmss
+BOOL date:(NSDate*)theDate isLaterInYearThan:(NSString*)yearlessDate {
NSDateFormatter* fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = #"MMddHHmmss";
NSString* theDateFormatted = [fmt stringFromDate:theDate];
return [theDateFormatted compareTo:yearlessDate] == NSOrderedDescending;
}
The usual caveats apply re timezone, 12/24 device setting, etc. It would be most optimal to make the DateFormatter a static object.

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.

Filter dates which are earlier than today?

In my application I have a list of NSDate instances. At one point I need to seperate the dates which are past to today ie [NSDate date] (earlier to morning 12)
And I have used the logic like below. I feel there must be a better logic than this, so help me if there is better solution.
I pass the date instance as an argument to this method which will return a BOOL value corresponding to my requirement.
-(BOOL)checkIfPast:(NSDate *)date
{
NSDate *today=[NSDate date];
NSUInteger dateFlags = NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit;
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components1=[gregorianCalendar components:dateFlags fromDate:today];
NSDateComponents *components2=[gregorianCalendar components:dateFlags fromDate:date];
if (components2.day-components1.day<0) {
return YES;
}
else
{
return NO;
}
}
BOOL checkIfTodayOrFuture(NSDate *date)
{
NSDate *now = [NSDate date];
NSUInteger dateFlags = NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay;
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorianCalendar components:dateFlags fromDate:now];
NSDate *midnight = [gregorianCalendar dateFromComponents:components];
return [date compare:midnight] == NSOrderedDescending;
}
If you have to make a lot of tests keep midnight around and just do the compare: on all of the dates.
Keep in mind that the result is not constant. For example, the user might change her timezone so the interval of "today" also changes.
See NSDate's earlierDate: method
Create the Date for 12Am and make a Compare. The result says asc or dsc. I think asc is the One You want

If statement with dates

what I am trying to do is make a if statement with dates using greater than less than signs. For some reason only the greater than sign works. Here is my code:
NSDate *currDate = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"HHmm"];
NSString *dateString = [dateFormatter stringFromDate:currDate];
NSLog(#"%#",dateString);
if (dateString < #"0810" && dateString > #"0800") {
NSLog(#"Homeroom");
}
else {
NSLog(#"no");
}
The output for this code would be if the time was 8:03:
2013-04-08 08:03:47.956 Schedule2.0[13200:c07] 0803
2013-04-08 08:03:47.957 Schedule2.0[13200:c07] no
If I were to make is so where it is only the greater then sign like this:
if (dateString > #"0800") {
NSLog(#"Homeroom");
}
else {
NSLog(#"no");
}
The output would be this:
2013-04-08 08:03:29.748 Schedule2.0[14994:c07] 0803
2013-04-08 08:03:29.749 Schedule2.0[14994:c07] Homeroom
create a NSDate object with the time 8:10 and one with 8:00. Now you can compare the given date with both these dates
if(([date0800 compare:date] == NSOrderingAscending) && [date0810 compare:date] == NSOrderingDescending) )
{
// date is between the other
}
to create the boundaries dates you can do this
NSDate *date = [NSDate date]; // now
NSDateComponents *components = [[NSCalendar currentCalendar] components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit ) fromDate:date];
components.hour = 8;
components.minute = 0;
NSDate *date0800 = [[NSCalendar currentCalendar] dateFromComponents: components];
components.minute = 10;
NSDate *date0810 = [[NSCalendar currentCalendar] dateFromComponents: components];
if you insist of using operators like < and >, you can use the timeinterval of the date objects.
if(([date0800 timeIntervalSince1970] < [date timeIntervalSince1970]) && ([date0810 timeIntervalSince1970] > [date timeIntervalSince1970]))
{
// date lays between the other two
}
but beware of checking == on it, as it could be faulty due to rounding errors.
Here you are comparing string objects, with < and >, which does not do what you are expecting. You can use NSDateComponents to get the hour and minute to compare those:
NSDate *today = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components =
[gregorian components:(NSHourCalendarUnit | NSMinuteCalendarUnit ) fromDate:today];
NSInteger hour = [weekdayComponents hour];
NSInteger minutes = [weekdayComponents minute];
BOOL homeroom = (hour == 8) && (minute < 10);
Or you can create a specific NSDate for 8:10 and 8:00 using NSDateFormater and using the compare: function.
NSString objects are objects, and when you compare objects with C comparison operators (==, >, <, etc.) you are comparing their addresses, not their values. You need to use compare, such as:
if ([dateString compare:#"0810"] == NSOrderedAscending &&
[dateString compare:#"0800"] == NSOrderedDescending) { ...
Though I'd recommend converting to NSDate objects in most cases if you want to compare dates and times.
You can't use > or < to compare string objects. That actually compares pointers so we won't get into why > 'works' and < 'doesn't'.
For this kind of date comparison use NSDateComponents
NSDateComponents Reference
Here's the gist of a category I wrote on NSDate. I found it made my code more readable.
https://gist.github.com/nall/5341477
#interface NSDate(SZRelationalOperators)
-(BOOL)isLessThan:(NSDate*)theDate;
-(BOOL)isLessThanOrEqualTo:(NSDate*)theDate;
-(BOOL)isGreaterThan:(NSDate*)theDate;
-(BOOL)isGreaterThanOrEqualTo:(NSDate*)theDate;
#end

Resources