NSTimeInterval seems to be wrong for last day of the given month- iOS - iphone

In my local database, I have a list of NSTimeInterval values saved.
I have to find out and fetch all records available in a given Month. The only problem is in fetching records for last day of the given month seems to be unavailable.
Lets say given month is December so I have to fetch all the records from 1st Dec to 31st Dec (Till 11:59PM)
I am using following implementation:
[self.dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSDate *startDate = [self.dateFormatter dateFromString:#"1-12-2012"];
NSDate *endDate = [self.dateFormatter dateFromString:#"31-12-2012"];
NSTimeInterval startDateTimeInterval = [startDate timeIntervalSince1970];
NSTimeInterval endDateTimeInterval = [endDate timeIntervalSince1970];
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"(mdate >= %f) AND (mdate <= %f)",startDateTimeInterval,endDateTimeInterval]];
I have noticed that endDateTimeInterval double value is pretty less as compared to saved value in the database for 31st (9AM). But howz it possible, I am expecting my endDateTime should be till 31st Dec 11:59 PM.
Please provide your inputs on this issue.

The NSDate objects you are creating implicitly have a time of 00:00. So the predicate search will not include the last day from time 00:01 to 23:59. The easiest change is to set the end date to the next day (first of next month) and change the predicate to a less than, instead of less than or equal.
[self.dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSDate *startDate = [self.dateFormatter dateFromString:#"1-12-2012"]; // start of range, inclusive
NSDate *endDate = [self.dateFormatter dateFromString:#"1-1-2013"]; // end of range, exclusive
...
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:#"(mdate >= %f) AND (mdate < %f)",startDateTimeInterval,endDateTimeInterval]];

Jason's answer will solve the problem but I think I've figured out the confusion: although in normal English a date usually specifies a whole day, in Cocoa terms an NSDate is an exact moment in time. So it has no length and a full description requires more detail than merely day/month/year. Most of the standard means of creating an NSDate offer precision to the nearest whole second, and obviously once you've converted to an 'NSTimeInterval` you can usually do better than that.
The NSLog is printing 30 because there are 30 whole days between the same time on the 1st of the month and the 31st, just like there's one whole day between the same time on the 1st and the 2nd, and zero whole days between the same time on the 1st and the 1st.
Jason's answer is therefore correct because it applies the time test of 'after the start of the first day of this month and before the start of the first day of the next month'. It's the 'the start of' bits that make the difference.

Related

How can validate NSDATE

How to find one text field value is within past 60 day excluding current date.
For example if I enter value in text field is 20-July-2012 using Date Picker.Then I click submit,it'll check that specific is date is within 60 days or not. If the values are entered which is before 60 days an alert message is displayed. The values are retrieved from api.
NSDate *today = [NSDate date];
NSTimeInterval dateTime;
if ([pickerDate isEqualToDate:today]) //pickerDate is a NSDate
{
NSLog (#"Dates are equal");
}
dateTime = ([pickerDate timeIntervalSinceDate:today] / 86400);
if(dateTime < 0) //Check if visit date is a past date, dateTime returns - val
{
NSLog (#"Past Date");
}
else
{
NSLog (#"Future Date");
}
Change the value of 86400 to suit your query.In this case, it is the number of seconds we want to compare.
First, convert the text into an NSDate. Then use
timeIntervalSinceDate:[NSDate dateWithTimeIntervalSinceNow:0]
There are a couple of ways to convert text into an NSDate. You can format the text correctly and then use dateWithString or you can convert everything into numbers, multiply them out, and one of the dateWithTimeInterval methods.
If you want the user to be able to enter "July" (plain text month) then you might want to write a method that converts months into their numerical equivalents with string matching.
NSDate *lastDate; //your date I hope you have created it
NSDate *todaysDate = [NSDate date];
NSTimeInterval lastDiff = [lastDate timeIntervalSinceNow];
NSTimeInterval todaysDiff = [todaysDate timeIntervalSinceNow];
NSTimeInterval dateDiff = lastDiff - todaysDiff; // number of seconds
int days = dateDiff/(60*60*24); // 5.8 would become 5 as I'm taking int
How do you define 60 days?
You may want to use NSCalendar -dateByAddingComponents:toDate:options: to ensure your 60 days really are 60 days.
NSCalendar also provides -components:fromDate: and -dateFromComponents: which are very nice when dealing with date components.
If 60 days do not need to be true calendar days (daylight saving time switches, astronomical time corrections, stuff like that), you can just have fun with NSDate and the time interval methods alone.

How to see if a date is beween two other dates, and the time used and the time remaining?

If I have set dates like Sunday Jan.29, 2012 2:00:00 PM and Friday Feb.3 2012 5:00:00 PM,
and get the present time, how to I get the spent time from the first date and the present and how do I get the remaining time from the present and the future date?
I have code to show but it is all wrong. There has to be a easy way to do it that I just cant see.
Thank you
Eric
You want to use functions from NSDate
for example:
//get time difference between someDate and now
NSTimeInterval diff = [someDate timeIntervalSinceNow];
//get difference between dates
NSTimeInterval diff2 =[someDate timeIntervalSinceDate: otherDate];
//comparing dates
NSDate * earlierDate = [someDate earlierDate: otherDate];
NSDate * laterDate = [someDate laterDate: otherDate];
If you have your dates available as NSDate objects, you can use timeIntervalSinceDate: to calculate the difference in seconds.
NSTimeInterval sinceThen = [firstDate timeIntervalSinceDate:[NSDate date]];
which will give you the time difference as an NSTimeInterval which is basically a double specifying the time in seconds. If the interval is negative, then firstDate is before now (which is the result of [NSDate date] otherwise it is in the future. If your date is not yet in NSDate form, you might employ an NSDateFormatter to do this (See here, parsing date strings).

NSDate : Add a day based on Time

In my app, I am getting a Date and start time of the same date and end time. The end time could be the time of very next day.
example : Date : 11/01/2011
start time : 5:30 PM
end time : 4:30 AM (of next day morning)
I am not getting the End Date.
How can I add one day into the start date based on the end time. I've referred many answers at SO but could not find the solution.
you should use this function
NSDate *endDate = [NSDate dateWithTimeIntervalSinceNow:86400];
here 86400 is 60(seconds)*60(minutes)*24(hours).If your startDate is not from current date then you can use this method
- (id)initWithTimeInterval:(NSTimeInterval)secsToBeAdded sinceDate:(NSDate *)anotherDate
now you are getting like this
example : Date : 11/01/2011
start time : 5:30 PM
end time : 4:30 AM (of next day morning)
so you can have two dates, represents start time and end time. Use below method to get time interval
- (NSTimeInterval)timeIntervalSince1970
now you have two time interval for two different dates, right? Now simply subtract it and you will get what you want.
Solved : according to Akkis's answer...
NSDate *startDate = [df dateFromString:startingDateTime];
NSDate *endDate = [df dateFromString:endingDateTime];
NSComparisonResult result;
result = [startDate compare:endDate];
if(result == NSOrderedDescending)
{
NSLog(#"newDate is greater");
endDate = [endDate dateByAddingTimeInterval:60*60*24];
}
Dirty (NO DST check) method: It's easier if you convert everything to common units (i.e. NSTimeInterval / double seconds). Check if end time is less than start time (converted to seconds from midnight). Subtract startSeconds from endSeconds, if result is negative add 24 hours worth of seconds (24*60*60 = 86400). Add result to start date/time.

Adding day to NSDate when a day doesn't equal 24 hours - iOS

I want to add a day to a NSDate object if its in the past (for an Alarm). However I ran into a problem if I just add 60*60*24 seconds. It adds 24 hours like what is usually wanted but in this case a day equals 23 hours. How do I fix this? Here is the following code:
while ([alarmTime compare:[[NSDate alloc] init]] == NSOrderedAscending) {
alarmTime = [alarmTime dateByAddingTimeInterval:(60*60*24)]; //if in the past add a day
NSLog(#"alarm %# is in the past, adding a day", alarmTime);
}
22:19:59.506: alarm 03/12/2011 12:00:00 AM is in the past, adding a day
22:19:59.506: alarm 03/13/2011 12:00:00 AM is in the past, adding a day
22:19:59.507: alarm 03/14/2011 01:00:00 AM is in the past, adding a day
22:19:59.507: alarm 03/15/2011 01:00:00 AM is in the past, adding a day
This isn't a bug, it is how NSDate's description method formats the date for your logging. Remember, NSDate just stores a time interval since a reference date, so adding a days worth of seconds will always increase it by a day. In your time zone, daylight savings time begins on 13 march, so 24 hours after midnight on the day before is 1 am.
Regarding your comment of how to fix this, what do you want to fix? The code in your question will add 24 hours to alarmTime until alarmTime is in the future. If your requirement is actually that the user enters, say, 5am, and you want alarmTime to be the next 5am, then this isn't really the way to go about it, you'd be better off synthesising a new date using NSDateComponents.
Here is the code I am now using that corrects this issue:
-(void) correctDate {
// Create an interval of one day
NSDateComponents *dayComponent = [[NSDateComponents alloc] init];
dayComponent.day = 1;
NSCalendar *theCalendar = [NSCalendar currentCalendar];
// if its in the past, add day
while ([alarmTime compare:[NSDate date]] == NSOrderedAscending) {
alarmTime = [theCalendar dateByAddingComponents:dayComponent toDate:alarmTime options:0]; //add a day
NSLog(#"alarm %# is in the past, adding a day", alarmTime);
}
}

NSCalendar getting day difference wrong

I'm trying to use [[NSCalendar currentCalendar] ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit forDate:date] on two different dates to see if they fall on the same day. However, if my time zone is different (say, somewhere in Germany), even though the dates are obviously the same, the days returned are different. If I use NSYearCalendarUnit instead of NSEraCalendarUnit on the same dates, the returned values are the same.
The only problem with using NSYearCalendarUnit is it returns the same value for the same day of different years, and it's not simple to determine the number of days between two dates if they fall on different years.
Any ideas what's wrong or how to more easily determine if two dates are on the same day, or to determine the number of days between them?
Example:
[NSTimeZone setDefaultTimeZone:[NSTimeZone timeZoneWithName:#"Europe/Berlin"]];
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date1 = [NSDate dateWithTimeIntervalSinceReferenceDate:300751200];
NSDate *date2 = [NSDate dateWithTimeIntervalSinceReferenceDate:300836062.388569];
NSLog(#"\nDate 1: %#\nDate 2: %#",date1,date2);
/*Output:
Date 1: 2010-07-14 00:00:00 +0200
Date 2: 2010-07-14 23:34:22 +0200
*/
int day1 = [cal ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit
forDate:date1];
int day2 = [cal ordinalityOfUnit:NSDayCalendarUnit inUnit:NSEraCalendarUnit
forDate:date2];
NSLog(#"\nDay 1: %i\nDay 2: %i",day1,day2);
/*Output:
Day 1: 733966
Day 2: 733967
*/
day1 = [cal ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit
forDate:date1];
day2 = [cal ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit
forDate:date2];
NSLog(#"\nDay 1:%i\nDay 2: %i",day1,day2);
/*Output:
Day 1: 195
Day 2: 195
*/
Filed a bug, but then I checked Date and Time Programming Guide again. If you use the code from listing 13 (similar to yours), it behaves wrong. But if you use listing 14, it works as expected.
EDIT: Conceptually, Apple is right. Jesus Christ (as everybody else) was born in absolute time, independent of timezones. So the new era started at the same point of time, regardless of timezones. New Year is at a different point of time in each timezone. This could explain differences between NSYearCalendarUnit and NSEraCalendarUnit. The problem is, that they did not explicitly state this in the docs.
See http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSCalendar_Class/Reference/NSCalendar.html:
“Discussion
The ordinality is in most cases not the same as the decomposed value of the unit. Typically return values are 1 and greater. For example, the time 00:45 is in the first hour of the day, and for units Hour and Day respectively, the result would be 1. An exception is the week-in-month calculation, which returns 0 for days before the first week in the month containing the date.”
In other words: 23:34:22 belongs to the last hour of day, coming up to 240. Time running over the zero is equivalent to: next day.
Maybe this could be treated as a bug: hours in a day running from the first over the twentytird to the zeroth? I suggest: fill in a bug report.