iOS: problem with NSDate and NSDateComponent - objective-c

NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease];
[components setTimeZone:[ NSTimeZone timeZoneForSecondsFromGMT:(+0*3600) ] ] ;
[components setYear:2011];
[components setDay:13];
[components setMonth:5];
NSDate *date1 = [gregorianCalendar dateFromComponents:components];
NSDate *date2 = [[NSDate alloc] init];
NSTimeInterval diff = [data2 timeIntervalSinceDate:date1];
NSString *intervalString = [NSString stringWithFormat:#"%f", diff];
int second = [intervalString intValue];
int period = second/3600/24;
NSLog(#"period:%d", period);
NSLog(#"date1:%#", data1);
NSLog(#"date2:%#", data2);
In consol the result is:
2011-05-12 10:57:00.406 Project[297:707] period:0;
2011-05-12 10:57:00.375 Project[297:707] data2:2011-05-12 08:56:52 +0000
2011-05-12 10:57:00.402 Project[297:707] data1:2011-05-13 00:00:00 +0000
I don't understand why period is "0", it must be "1"; Can you help me?

NSTimeInterval is just a double, so you shouldn't need to convert it to a string then back to an int.
What happens if you do something like this:
NSTimeInterval diff = [data2 timeIntervalSinceDate:date1];
int period = (int)diff/3600/24;
NSLog(#"period:%d", period);
Also if the interval is diff is less than 3600*24 the result of diff/3600/24 will be less than 1, so the int value will be flattened to 0.

date2 is the current date. No idea why period should be one here.
At the time of this writing, diff is approx. -53000. Dividing it brings it to zero as you get and is expected.
Also keep in mind that NSTimeInterval is a floating point number, and you are converting it through a string to an integer, which will drop off the fractions.
And there is no point in doing this conversion through a string - just use int seconds = (int) diff;.
Please copy/paste your code directly, as you refer to data1and data2, but your variables are called date1 and date2. But then, this might already be your bug, if those variables are declared elsewhere.

Related

How to compare two times in iOS

I am trying to compare two times in iOS. I have list of times in my array i just want to check current time is matching to the any one the array value. can any help how to do that. i searched whole internet i did't get any idea.
I saw this question answer but i can't get a exact result.
According to Apple documentation of NSDate compare:
Returns an NSComparisonResult value that indicates the temporal ordering of the receiver and another given date.
- (NSComparisonResult)compare:(NSDate *)anotherDate
Parameters anotherDate
The date with which to compare the receiver. This value must not be nil.
Return Value
If:
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
In other words:
if ([date1 compare:date2]==NSOrderedSame) ...
Note that it might be easier to read and write this :
if ([date2 isEqualToDate:date2]) ...
-(NSString *)determineDateFromstring:(long long)date
{
NSTimeInterval interval=date;
NSDate *currentTime=[NSDate dateWithTimeIntervalSince1970:interval/1000];
NSLocale *gbLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_GB"];
NSNumber *myDateInString=[NSNumber numberWithLongLong:[[NSDate date] timeIntervalSince1970]*1000];
NSTimeInterval inte=[myDateInString longLongValue];
NSDate *todayTime=[NSDate dateWithTimeIntervalSince1970:inte/1000];
NSCalendar *currentcalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [currentcalendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:todayTime];
int currentday=[components day];
int currentyear=[components year];
NSCalendar *paramtercalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *parametercomponents = [paramtercalendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:currentTime];
int currentday1=[parametercomponents day];
int currentyear1=[parametercomponents year];
if (currentday==currentday1) {
Nslog(date are same);
}else if(currentyear==currentyear1) {
Nslog(year are same);
}else{
}
}
if u want to check two date are equal or not then u can compare NStimeIntervals(long long values). if same then time ,date and year are same otherwise different.
I hope this answer will be the right to your question.......
Why don't you check the interval since 1970 and compare the integer value..
long long int i = [[NSDate date] timeIntervalSince1970];
I hope this will help.Also if you have values in form of NSString then you first need to convert them to NSDate
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"yyyy-MM-dd HH:mm:ssSSSSSS";
NSDate *d = [dateFormatter dateFromString:#"your date string"];

Problems formatting dates

Here is the set up, I have a JSON feed I am using and I want to find the difference between two specific dates called posted_date and planned_expiration_date. They are in an odd format I so I thought I could truncate them down to just the date.I could then use NSTimeInterval to find the difference in seconds.
// Time Interval Left
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
NSString *startDate = [firstPerson objectForKey:#"posted_date"];
NSString *endDate = [firstPerson objectForKey:#"planned_expiration_date"];
//Ammend the strings to YYYY-MM-DD
[formatter setDateFormat:#"yyyy-mm-dd"];
int newlength = 9;
NSDate *startDateAmmended =[formatter dateFromString:[startDate substringFromIndex:newlength]];
NSDate *endDateAmmended = [formatter dateFromString:[endDate substringFromIndex:newlength]];
Here is the bit I'm not too sure about. The date appears something like this "2013-06-07T13:40:01Z" straight from the feed. I don't know how to deal with the T and Z chars in the date formatter method so I truncate the string with substringFromIndex to make it 10 chars and then attempted the following code.
//Difference in Date
NSTimeInterval *startDifference = [startDateAmmended timeIntervalSinceNow];
NSTimeInterval *endDifference = [endDateAmmended timeIntervalSinceNow];
NSTimeInterval timeDifferenceInSeconds = startDifference - endDifference;
I get the following error, .../JSONParser/ViewController.m:52:21: Initializing 'NSTimeInterval *' (aka 'double *') with an expression of incompatible type 'NSTimeInterval' (aka 'double') at the first two calls to NSTimeInterval.
I am sure I'm going wrong in a few places and I'm sure this isn't the easiest method of doing it. Could anyone recommend how I would fix this issue or an easier way to go about getting the differences between dates?
Your error comes from your lines that say:
NSTimeInterval *startDifference = [startDateAmmended timeIntervalSinceNow];
NSTimeInterval *endDifference = [endDateAmmended timeIntervalSinceNow];
They should be:
NSTimeInterval startDifference = [startDateAmmended timeIntervalSinceNow];
NSTimeInterval endDifference = [endDateAmmended timeIntervalSinceNow];
Or, more simply, don't define those two difference variables at all, and just use:
NSTimeInterval timeDifferenceInSeconds = [endDateAmmended timeIntervalSinceDate:startDateAmmended];
To calculate the difference between two ISO 8601 / RFC 3339 date strings, you can do:
NSDate *startDate = [self dateFromISO8601String:#"2013-06-01T16:27:35Z"];
NSDate *endDate = [self dateFromISO8601String:#"2013-06-07T13:40:01Z"];
NSTimeInterval elapsed = [endDate timeIntervalSinceDate:startDate];
NSLog(#"Time elapsed (in seconds) is %.0f", elapsed);
where dateFromISO8601String is defined as:
- (NSDate *)dateFromISO8601String:(NSString *)string
{
static NSDateFormatter *formatter = nil;
if (formatter == nil)
{
formatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
formatter.locale = enUSPOSIXLocale;
formatter.dateFormat = #"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'";
formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
}
return [formatter dateFromString:string];
}
You can get the difference in seconds between two NSDate objects like this:
double difference = [startDateAmmended timeIntervalSinceDate:endDateAmmended];
Note that with the substring operation you don't have the time, only the date, so the difference will be in seconds but with steps of whole days.

NSDate compare is not working well

I've read all the questions and answer and all the tutorial about this subject, but for some reason it's not working for me. always showing me that the two dates are the same date!
Please some one help me to figure it out, I just want to check if one is bigger than the other (including date and time - without seconds) or if they are equal.
This is my code:
- (BOOL)isEndDateIsBiggerThanCurrectDate:(NSDate *)checkEndDate
{
NSString *endd = [NSDateFormatter localizedStringFromDate:checkEndDate
dateStyle:NSDateFormatterShortStyle
timeStyle:NSDateFormatterShortStyle];
NSString *curreeeent = [NSDateFormatter localizedStringFromDate:[NSDate date]
dateStyle:NSDateFormatterShortStyle
timeStyle:NSDateFormatterShortStyle];
NSDateFormatter * df = [[NSDateFormatter alloc]init];;
NSDate * newCurrent = [df dateFromString:endd];
NSDate * newEnd = [df dateFromString:curreeeent];
switch ([newCurrent compare:newEnd])
{
case NSOrderedAscending:
return YES;
break;
case NSOrderedSame:
return NO;
break;
case NSOrderedDescending:
return NO;
break;
}
}
Thank you very much!
For this, you have to use NSCalender.
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger desiredComponents = (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit);
NSDateComponents *firstComponents = [calendar components:desiredComponents fromDate:[NSDate date]];
NSDateComponents *secondComponents = [calendar components:desiredComponents fromDate: checkEndDate];
NSDate *first = [calendar dateFromComponents:firstComponents];
NSDate *second = [calendar dateFromComponents:secondComponents];
NSComparisonResult result = [first compare:second];
if (result == NSOrderedAscending) {
//checkEndDate is before now
} else if (result == NSOrderedDescending) {
//checkEndDate is after now
} else {
//both are same
}
You should really be using time intervals rather than converting between dates and strings.
Something like the following should suit your needs:
//current time
NSDate *now = [NSDate date];
//time in the future
NSDate *distantFuture = [NSDate distantFuture];
//gather time interval
if([now timeIntervalSinceDate:distantFuture] > 0)
{
//huzzah!
}
I've got the answer, just checking the exact time between two dates and compare it.
- (BOOL)isEndDateIsSmallerThanCurrent:(NSDate *)checkEndDate
{
NSDate* enddate = checkEndDate;
NSDate* currentdate = [NSDate date];
NSTimeInterval distanceBetweenDates = [enddate timeIntervalSinceDate:currentdate];
double secondsInMinute = 60;
NSInteger secondsBetweenDates = distanceBetweenDates / secondsInMinute;
if (secondsBetweenDates == 0)
return YES;
else if (secondsBetweenDates < 0)
return YES;
else
return NO;
}
Why don't you change the dates into time interval since 1970 and sort by that. Extremely simple number compare, much quicker than string compare, and they will always sort correct, not like 1,10,11,2,21,22,3,....
NSDate *now = [NSDate date];
NSTimeInterval ti = [now timeIntervalSince1970];
Thats it. No new object creations, much quicker and much less taxing on the cpu.
See here how you get rid of seconds, but it is easy because you have numbers, for seconds. See here How to set seconds to zero for NSDate

Get number of days between two NSDate dates in a particular timezone

I found the codes to calculate days difference between two dates here.
I write a method :
-(NSInteger)daysWithinEraFromDate:(NSDate *) startDate toDate:(NSDate *) endDate
{
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSInteger startDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:startDate];
NSInteger endDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:endDate];
return endDay-startDay;
}
This method has a problem: it can't consider the timezone thing. Even I add a line like this:
[gregorian setTimeZone:[NSTimeZone localTimeZone]];
My test code is like this:
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSString *strDate = #"2012-09-03 23:00:00";
NSDate *dateStart = [dateFormat dateFromString:strDate];
strDate = #"2012-09-04 01:00:00";
NSDate *dateEnd = [dateFormat dateFromString:strDate];
NSLog(#"Days difference between %# and %# is: %d days",[dateFormat stringFromDate:dateStart],[dateFormat stringFromDate:dateEnd],[self daysWithinEraFromDate:dateStart toDate:dateEnd]);
The result is:
Days difference between 2012-09-03 23:00:00 and 2012-09-04 01:00:00 is: 0 days
I want to get 1 day as result by the number of midnights between the two dates. My timezone is GMT +8. But this calculation is based on GMT, so I get the wrong days number. Is there anyway to solve this problem? Thank you.
Scott Lemmon's method can solve my problem. I rewrite my code like this:
-(NSInteger)daysWithinEraFromDate:(NSDate *) startDate toDate:(NSDate *) endDate
{
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setTimeZone:[NSTimeZone localTimeZone]];
NSDate *newDate1 = [startDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];
NSDate *newDate2 = [endDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];
NSInteger startDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:newDate1];
NSInteger endDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:newDate2];
return endDay-startDay;
}
If the time zone offset isn't working, how about just add or subtract it manually instead?
In your case NSDate *newDate = [oldDate dateByAddingTimeInterval:(-8 * 60 * 60)]; to subtract off your +8 hours.
Or if you want to find the GMT offset automatically as well then it would simply be NSDate *newDate = [oldDate dateByAddingTimeInterval:(-[[NSTimeZone localTimeZone] secondsFromGMT])
Another thought:
A perhaps easier solution would be to just disregard the time information altogether. Just set it to the same arbitrary number for both dates, then as long as the dates come from the same timezone you will always get the correct number of mid-nights between them, regardless of GMT offset.
What you really want is the NSDate method timeIntervalSinceDate:, and take that result and if it's more than 0 but less than 86400 (the number of seconds in a day), that's one day. Otherwise, divide your result by 86400 and you'll get the number of days.
The way you currently have your code, there's only 2 hours between the two days and that's why you are seeing a result of 0 and not one.
Edit - and to determine if midnight has happened, let's try this function I just wrote off the top of my head:
- (NSDate *) getMidnightDateFromDate: (NSDate *) originalDate
{
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSIntegerMax fromDate:originalDate];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
NSDate *midnight = [[NSCalendar currentCalendar] dateFromComponents:components];
return(midnight);
}
- (BOOL) howManyDaysDifferenceBetween: startDate and: endDate
{
NSDate * firstMidnight = [self getMidnightDateFromDate: startDate];
NSDate * secondMidnight = [self getMidnightDateFromDate: endDate];
NSTimeInterval timeBetween = [firstMidnight timeIntervalSinceDate: secondMidnight];
NSInteger numberOfDays = (timeBetween / 86400);
return(numberOfDays);
}
which I'm basing off Dave Delong's answer to this question. No guarantees that my code will work (I didn't test it), but I think the concept is sound.

iOS: Compare two dates

I have a NSDate that I must compare with other two NSDate and I try with NSOrderAscending and NSOrderDescending but if my date is equal at other two dates?
Example: if I have a myDate = 24/05/2011 and other two that are one = 24/05/2011 and two 24/05/2011 what can I use?
According to Apple documentation of NSDate compare:
Returns an NSComparisonResult value that indicates the temporal ordering of the receiver and another given date.
- (NSComparisonResult)compare:(NSDate *)anotherDate
Parameters anotherDate
The date with which to compare the
receiver. This value must not be nil.
If the value is nil, the behavior is
undefined and may change in future
versions of Mac OS X.
Return Value
If:
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
In other words:
if ([date1 compare:date2] == NSOrderedSame) ...
Note that it might be easier in your particular case to read and write this :
if ([date2 isEqualToDate:date2]) ...
See Apple Documentation about this one.
After searching, I've got to conclusion that the best way of doing it is like this:
- (BOOL)isEndDateIsSmallerThanCurrent:(NSDate *)checkEndDate
{
NSDate* enddate = checkEndDate;
NSDate* currentdate = [NSDate date];
NSTimeInterval distanceBetweenDates = [enddate timeIntervalSinceDate:currentdate];
double secondsInMinute = 60;
NSInteger secondsBetweenDates = distanceBetweenDates / secondsInMinute;
if (secondsBetweenDates == 0)
return YES;
else if (secondsBetweenDates < 0)
return YES;
else
return NO;
}
You can change it to difference between hours also.
If you want to compare date with format of dd/MM/yyyy only, you need to add below lines between NSDate* currentdate = [NSDate date]; && NSTimeInterval distance
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/yyyy"];
[dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:#"en_US"]
autorelease]];
NSString *stringDate = [dateFormatter stringFromDate:[NSDate date]];
currentdate = [dateFormatter dateFromString:stringDate];
I take it you are asking what the return value is in the comparison function.
If the dates are equal then returning NSOrderedSame
If ascending ( 2nd arg > 1st arg ) return NSOrderedAscending
If descending ( 2nd arg < 1st arg ) return NSOrderedDescending
I don't know exactly if you have asked this but if you only want to compare the date component of a NSDate you have to use NSCalendar and NSDateComponents to remove the time component.
Something like this should work as a category for NSDate:
- (NSComparisonResult)compareDateOnly:(NSDate *)otherDate {
NSUInteger dateFlags = NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit;
NSCalendar *gregorianCalendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDateComponents *selfComponents = [gregorianCalendar components:dateFlags fromDate:self];
NSDate *selfDateOnly = [gregorianCalendar dateFromComponents:selfComponents];
NSDateComponents *otherCompents = [gregorianCalendar components:dateFlags fromDate:otherDate];
NSDate *otherDateOnly = [gregorianCalendar dateFromComponents:otherCompents];
return [selfDateOnly compare:otherDateOnly];
}
NSDate actually represents a time interval in seconds since a reference date (1st Jan 2000 UTC I think). Internally, a double precision floating point number is used so two arbitrary dates are highly unlikely to compare equal even if they are on the same day. If you want to see if a particular date falls on a particular day, you probably need to use NSDateComponents. e.g.
NSDateComponents* dateComponents = [[NSDateComponents alloc] init];
[dateComponents setYear: 2011];
[dateComponents setMonth: 5];
[dateComponents setDay: 24];
/*
* Construct two dates that bracket the day you are checking.
* Use the user's current calendar. I think this takes care of things like daylight saving time.
*/
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDate* startOfDate = [calendar dateFromComponents: dateComponents];
NSDateComponents* oneDay = [[NSDateComponents alloc] init];
[oneDay setDay: 1];
NSDate* endOfDate = [calendar dateByAddingComponents: oneDay toDate: startOfDate options: 0];
/*
* Compare the date with the start of the day and the end of the day.
*/
NSComparisonResult startCompare = [startOfDate compare: myDate];
NSComparisonResult endCompare = [endOfDate compare: myDate];
if (startCompare != NSOrderedDescending && endCompare == NSOrderedDescending)
{
// we are on the right date
}
Check the following Function for date comparison first of all create two NSDate objects and pass to the function:
Add the bellow lines of code in viewDidload or according to your scenario.
-(void)testDateComaparFunc{
NSString *getTokon_Time1 = #"2016-05-31 03:19:05 +0000";
NSString *getTokon_Time2 = #"2016-05-31 03:18:05 +0000";
NSDateFormatter *dateFormatter=[NSDateFormatter new];
[dateFormatter setDateFormat:#"yyyy-MM-dd hh:mm:ss Z"];
NSDate *tokonExpireDate1=[dateFormatter dateFromString:getTokon_Time1];
NSDate *tokonExpireDate2=[dateFormatter dateFromString:getTokon_Time2];
BOOL isTokonValid = [self dateComparision:tokonExpireDate1 andDate2:tokonExpireDate2];}
here is the function
-(BOOL)dateComparision:(NSDate*)date1 andDate2:(NSDate*)date2{
BOOL isTokonValid;
if ([date1 compare:date2] == NSOrderedDescending) {
//"date1 is later than date2
isTokonValid = YES;
} else if ([date1 compare:date2] == NSOrderedAscending) {
//date1 is earlier than date2
isTokonValid = NO;
} else {
//dates are the same
isTokonValid = NO;
}
return isTokonValid;}
Simply change the date and test above function :)