iOS - Comparing NSDate with another NSDate - ios

i know how to get difference between two NSDate as follow
NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:anyPreviousDate];
and i know it will return me NSTimeInterval in positive seconds. what I want to know is what it will return if my anyPreviousDate is greater than [NSDate date] i.e. anyPreviousDate has not been passed it will come in future.
just curious if anybody has done that before.
Thanks in advance.

I have found another very nice approach to do the same...
here is the code, i thought to share it with stackoverflow.
Cocoa has couple of methods for this:
in NSDate
– isEqualToDate:
– earlierDate:
– laterDate:
– compare:
When you use - (NSComparisonResult)compare:(NSDate *)anotherDate ,you get back one of these:
The receiver and anotherDate are exactly equal to each other, NSOrderedSame
The receiver is later in time than anotherDate, NSOrderedDescending
The receiver is earlier in time than anotherDate, NSOrderedAscending.
example:
NSDate * now = [NSDate date];
NSDate * mile = [[NSDate alloc] initWithString:#"2001-03-24 10:45:32 +0600"];
NSComparisonResult result = [now compare:mile];
NSLog(#"%#", now);
NSLog(#"%#", mile);
switch (result)
{
case NSOrderedAscending: NSLog(#"%# is in future from %#", mile, now); break;
case NSOrderedDescending: NSLog(#"%# is in past from %#", mile, now); break;
case NSOrderedSame: NSLog(#"%# is the same as %#", mile, now); break;
default: NSLog(#"erorr dates %#, %#", mile, now); break;
}
[mile release];

if([previousDate compare:[NSDate date]] == NSOrderedDescending){
// Previous date is greater than current date.i.e. previous date
//is still to come
}else{
//Previous date is smaller then current date.i.e. previous date
//has passed.
}
compare method of NSDate object returns NSComparisonResult, which is an enum.
NSComparisonResult has following values.
NSOrderedSame is returned if left and right operands are equal
NSOrderedAscending is returned if left operand is smaller than the right operand
NSOrderedDescending is returned if ft operand is greater than the right operand

If anyPreviousDate is actually ten seconds in the future, then your code will return -10.0. It happens quite often that you define NSDates that are some time in the future (for example to do something one minute from now), so this isn't unusual at all.

this's a screenshot to see
NSDate * savedDate = [recordsDic[record.transactionId] modifiedDate];
NSDate * newDate = record.modifiedDate;
NSComparisonResult comparisonResult = [newDate compare:savedDate];
NSTimeInterval timeInterval = [newDate timeIntervalSinceDate:savedDate];
NSLog(#"\nsavedDate: %# \nnewDate : %# \n===> timeInterval: %f",savedDate,newDate,timeInterval);
if (comparisonResult == NSOrderedSame) {
NSLog(#"they are same!!!!");
} else {
NSLog(#"they are NOT same!!!!");
}
Console log:
2019-04-11 17:26:47.903059+0800 xxxxx[19268:24419134]
savedDate: Thu Apr 11 15:47:23 2019
newDate : Thu Apr 11 15:47:23 2019
===> timeInterval: 0.000365
2019-04-11 17:26:47.903193+0800 xxxxx[19268:24419134] they are NOT same!!!!
Can you believe this!? but That's true, I spent almost a whole day figuring this out. cause this won't consistently happen!!!
so I strongly recommend:
1. Do NOT use instance method "- (NSComparisonResult)compare:(NSDate *)other;" to compare, you would see something really wired and you can not figure out.
2. timeIntervalSinceDate is more precise.

Related

Find nearest date in string array

So, I've got an sorted NSArray that contains NSString object (downloaded from a server), with the format: yyyy-MM-dd.
It's pretty much like this:
NSArray <NSString *> *dates = #[#"2017-06-25",
#"2017-06-26",
#"2017-06-27",
#"2017-06-28",
#"2017-06-30",
#"2017-07-01",
#"2017-07-02",
#"2017-07-03"];
So, today is 2017-06-29, and it's not in the array. How do I get the next nearest one? In this sample is 06-30, but it might be 07-01 if 06-30 doesn't exist...
Update
So people are asking me about what I've attempted to do. So it's like this (not very effective, but work)
Find if today is in the array (if yes, return)
Loop dates:
2.1 Convert dateString to date
2.2 Compare if date is greater than today => return if YES
If not found in step#2, return last object in dates array.
Actual code:
NSDateFormatter *formatter = [NSDateFormatter new];
formatter.dateFormat = #"yyyy-MM-dd";
NSDate *today = [NSDate date];
NSUInteger index = [dates indexOfObject:[formatter stringFromDate:today]];
// Step 1
if (index == NSNotFound) {
// Step 2: Loop converted
NSInteger i = 0;
for (NSString *date in dates) {
// Step2.1: find the next nearest date's index
NSDate *convertedDate = [formmater dateFromString:date];
// Step2.2: Compare
if ([convertedDate intervalSinceDate:today] > 0) {
index = i;
break;
}
i++;
}
// Step 3: Still not found, index = last index
if (index == NSNotFound) index = i-1;
}
return dates[index];
This doesn't look so good because I might reload the dates array pretty much. Can I have a better solution?
Your algorithm is not bad, though your code doesn't appear to implement it (no sort?). If you'd like to improve it consider this:
First there is probably little point in doing a first scan to check for an exact match - that is potentially a linear search (implemented by indexOfObject:) through an unordered array, and if it fails you have to scan again for a close match, just do them at the same time.
Second there is no advantage in sorting, which is at best O(NlogN), as a linear search, O(N), will find you the answer you need.
Here is a sketch:
Convert the date you are searching for from NSString to NSDate, call it, say, target
Set bestMatch, an NSString to nil. Set bestDelta, an NSTimeInterval, to the maximum possible value DBL_MAX.
Iterate over your dates array:
3.1. Convert the string date to an NSDate, say date
3.2. Set delta to the difference between date and target
3.3. If delta is zero you have an exact match, return it
3.4. If delta is better than bestDelta, update bestDelta and bestMatch
After iteration bestMatch is the best match or nil if there wasn't one.
That is a single iteration, O(N), early return on exact match.
HTH
Please find the simplest solution for your problem. Updated solution based on sorting order!
We can use NSPredicate Block to solve.
static NSDateFormatter* formatter = nil;
static NSDate* today = nil;
// return an NSDate for a string given in yyyy-MM-dd
- (NSDate *)dateFromString:(NSString *)string {
if (formatter == nil) {
formatter = [NSDateFormatter new];
formatter.dateFormat = #"yyyy-MM-dd";
}
return [formatter dateFromString:string];
}
// Helps to return today date.
-(NSDate*) getTodayDate {
if (today == nil) {
today = [NSDate date];
}
return today;
}
// Helps to find nearest date from Array using Predicate
-(NSString*)findNearestDate:(NSArray*)dateArray {
today = nil;
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(NSString *dateString, NSDictionary *bind){
// this is the important part, lets get things in NSDate form so we can use them.
NSDate *dob = [self dateFromString:dateString];
NSComparisonResult result = [[self getTodayDate] compare:dob];
if (result == NSOrderedSame || result == NSOrderedAscending) {
return true;
}
return false;
}];
// Apply the predicate block.
NSArray *futureDates = [dateArray filteredArrayUsingPredicate:predicate];
if ([futureDates count] > 0) {
// Sort the Array.
futureDates = [futureDates sortedArrayUsingSelector: #selector(compare:)];
return [futureDates objectAtIndex:0];
}
return nil;
}
NSArray <NSString *> *dates = #[#"2017-06-25",
#"2017-06-26",
#"2017-06-27",
#"2017-06-28",
#"2017-06-30",
#"2017-07-01",
#"2017-07-02",
#"2017-07-03"];
NSLog(#"Nearest Date: %#", [self findNearestDate:dates]);
Answer: Nearest Date: 2017-06-30
1. Input
So you have an array of NSString like this
// input
NSArray<NSString *> * words = #[#"2017-06-25",
#"2017-06-26",
#"2017-06-27",
#"2017-06-28",
#"2017-06-30",
#"2017-07-01",
#"2017-07-02",
#"2017-07-03"];
2. Converting the array of NSString into an array of NSDate
First of all you need to convert the each input string into an NSDate
NSMutableArray<NSDate *> * dates = [NSMutableArray new];
NSDateFormatter * dateFormatter = [NSDateFormatter new];
dateFormatter.dateFormat = #"yyyy-MM-dd";
for (NSString * word in words) {
[dates addObject:[dateFormatter dateFromString:word]];
}
3. Finding the nearestDate
Now you can find the nearest date
NSDate * nearestDate = nil;
NSTimeInterval deltaForNearesttDate = 0;
NSDate * now = [NSDate new];
for (NSDate * date in dates) {
NSTimeInterval delta = fabs([date timeIntervalSinceDate:now]);
if (nearestDate == nil || (delta < deltaForNearesttDate)) {
deltaForNearesttDate = delta;
nearestDate = date;
}
}
4. Conclusion
The result is into the nearestDate variable so
NSLog(#"%#", nearestDate);
Wed Jun 28 00:00:00 2017

How to compare time greater than 3 sec in ios

How to compare time is greater than 3 sec in ios.
Time is like "2016-05-10 05:31:14". I got code for comparing like greater or less with specific time but how i will achieve it is greater than 3 sec etc.
You can get seconds difference between two dates by
NSDate *someDate;//Some Date
NSLog(#"Seconds --> %f",[[NSDate date] timeIntervalSinceDate: someDate]);
Please try this one. May be Its possible for you:
NSDate* timeNow = [NSDate date];
// If less than 30 seconds, do something
if ([timeNow timeIntervalSinceDate:anEarlierTime] < 30.0f)
{
// Do something
}
- (BOOL)isEndDateIsSmallerThanCurrent:(NSDate *)checkEndDate
{
NSDate* enddate = checkEndDate;
NSDate* currentdate = [NSDate date];
NSTimeInterval distanceBetweenDates = [enddate timeIntervalSinceDate:currentdate];
double secondsInMinute = 60;
// secondsBetweenDates is your seconds difference
NSInteger secondsBetweenDates = distanceBetweenDates / secondsInMinute;
if (secondsBetweenDates == 0)
return YES;
else if (secondsBetweenDates < 0)
return YES;
else
return NO;
}
Here, secondsBetweenDates is your difference in seconds. You can check that it is smaller or greater or equal than 3.
You can get difference here in hours also!
Hope this will help :)

ios8 - seeing if a record is past or future

I'm parsing an array and want to weed out records from before now.
I've got this code:
int i = 0;
for (i=0; i < tempArray.count; i++) {
currentObjectArray = tempArray[i];
NSString *dateString = [currentObjectArray valueForKey:#"ScheduleTime" ];
NSDate *schedule = [dateFormatter dateFromString:dateString];
NSLog(#"schedule: %lu", (unsigned long) schedule );
NSLog(#"now: %lu", (unsigned long)[NSDate date] );
NSTimeInterval distanceBetweenDates = [schedule timeIntervalSinceDate: schedule];
NSLog(#"distanceBetweenDates: %lu", (unsigned long)distanceBetweenDates );
result:
schedule: 16436914033316069376
now: 6174145184
distanceBetweenDates: 0
but the two resulting numbers are incorrect, thus the result is incorrect. Could someone please tell me what I'm doing wrong? Thanks
UPDATE: Thanks to answers below, I've updated my code as follows:
NSString *dateString = [currentObjectArray valueForKey:#"ScheduleTime" ];
NSDate *schedule = [dateFormatter dateFromString:dateString];
float s = [schedule timeIntervalSince1970];
NSLog(#" %f", s );
NSTimeInterval timeInterval = [currentObjectArray timeIntervalSinceNow];
if (timeInterval > 0) {
NSLog(#"YES");
} else {
NSLog(#"NO");
The schedule date format is: "YYYY-MM-DD'T'HH:mm:ss"
Update2: I forgot to add in the local time zone. Thanks for all the help.
These two lines don't do what you think they do.
NSLog(#"schedule: %lu", (unsigned long) schedule );
NSLog(#"now: %lu", (unsigned long)[NSDate date] );
Performing this type cast is asking the system to return you an unsigned long representation of the pointer to the object, which is a memory address and not at all related to time. It is likely that you actually wanted to ask for the NSTimeInterval values.
NSLog(#"schedule: %f", [schedule timeIntervalSince1970] );
NSLog(#"now: %f", [[NSDate date] timeIntervalSince1970] );
Compounding your confusion, you have also misunderstood this line:
NSTimeInterval distanceBetweenDates = [schedule timeIntervalSinceDate: schedule];
You are asking the system to tell you how many seconds are between schedule and schedule; which is obviously always going to be 0 since they are identical. Instead, you probably meant one of:
NSTimeInterval distanceBetweenDates1 = [[NSDate date] timeIntervalSinceDate:schedule];
NSTimeInterval distanceBetweenDates2 = [schedule timeIntervalSinceDate:[NSDate date]];
You only need to check if the time interval is negative or positive to determine if a time comes before or after, respectively.
- (BOOL)isDateInPast:(NSDate *)date {
NSTimeInterval timeInterval = [date timeIntervalSinceNow];
if (timeInterval < 0) {
return YES;
} else {
return NO;
}
}
Note that this doesn't check the condition where the time interval is 0 (the present).
EDIT: Adding to this for further clarification. Your loop code could look something like this...
NSMutableArray *datesOnlyInFuture = [NSMutableArray array];
for (NSDate *date in dateArray) {
if (![self isDateInPast:date]) {
[datesOnlyInFuture addObject:date];
}
}
NSLog(#"Future only dates: %#", datesOnlyInFuture);
This will actually create a new array for you. Clearly plenty of optimizations should be made. For example timeIntervalSinceNow is going to be different each time it is called, so you could pass in a constant date that is set before the loop starts so you're always checking against the same date/time.

NSTimeInterval in seconds between dates = nan

NSTimeInterval executionTime = [self.EndDownloadTime timeIntervalSinceDate:self.StartDownloadTime];
NSLog(#"Execution Time: %f", executionTime);
Result is always "nan". When i switch EndDownloadTime and StartDownloadTime, time is "0.00000"
StartDownloadTime and EndDownloadTime are types of NSDate.
How do i get the seconds between the two dates?
Thank you in advance.
The simplest solution is a better method, check the docs when things seem complicated:
NSTimeInterval executionTime = [self.EndDownloadTime timeIntervalSinceDate:self.StartDownloadTime];
When you are debugging a problem and everything looks correct but the code is failing then an assumption must be wrong. There are two assumptions here (at least): the values of self.EndDownloadTime and self.StartDownloadTime. NSLog them or use the debugger examining the values as you step through.
Check everything:
NSLog(#"StartDownloadTime: %#", self.StartDownloadTime);
NSLog(#"StartloadTimeInterval: %f", [self.StartDownloadTime timeIntervalSince1970]);
NSLog(#"EndDownloadTime: %#", self.EndDownloadTime);
NSLog(#"EndDownloadTimeInterval: %f", [self.EndDownloadTime timeIntervalSince1970]);
NSTimeInterval executionTime = [self.EndDownloadTime timeIntervalSince1970] - [self.StartDownloadTime timeIntervalSince1970];
NSLog(#"Execution Time: %f", executionTime);
Note: In Cocoa* properties and variables and method names by convention begin with a lower case letter, class names with an uppercase letter. This makes it easier for others to understand your code.
Your code looks right. Try this and print value of variables to know if the two dates are correct.
NSTimeInterval executionTime = [self.EndDownloadTime timeIntervalSince1970] - [self.StartDownloadTime timeIntervalSince1970];
NSLog(#"Execution Time: %f", executionTime);

Find object in array with closest date to current time [duplicate]

This question already has answers here:
NSDate finding nearest date to today
(5 answers)
Closed 7 years ago.
I have an array of objects, each with an NSDate property called "date".
How can I find the object with the closest date to current time?
This will leave closestObject with the object that has the closest date. If you don't want past dates, then get rid of the ABS and make sure interval is positive.
MyObjectType *closestObject;
NSTimeInterval closestInterval = DBL_MAX;
for (MyObjectType *myObject in array) {
NSTimeInterval interval = ABS([myObject.date timeIntervalSinceDate:[NSDate date]]);
if (interval < closestInterval) {
closestInterval = interval;
closestObject = myObject;
}
}
- (NSDate *)closestDateFromArray:(NSArray *)dateArray
{
double smallestDifference = DBL_MAX; // thanks bgfriend0
NSDate *closestDate = nil;
for (NSDate *date in dateArray) {
// suggested by Henri Normak
if ([date timeIntervalSinceNow] <= someThresholdValue) {
return date;
// you could set some value that is a "good enough" value.
// i.e. if the date IS NOW then nothing is going to be closer.
}
if (ABS([date timeIntervalSinceNow]) < smallestDifference) {
smallestDifference = ABS([date timeIntervalSinceNow]);
closestDate = date;
}
}
return closestDate;
}
Something like this should do the trick.
If the array is an array of objects that have a date property then you can do exactly the same just get the date out of the object to compare.

Resources