How i campare two dates in Iphone? - iphone

I want to set date and time two days after my current date and time.How i set it using NSDate and dateformatter. I want compare date after two days, it was perviously set or not.
I write code now for it,
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDate *pickerDate = [self.datePicker date];
NSDateComponents *dateComponents = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:pickerDate];
NSDateComponents *timeComponents = [calendar components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:pickerDate];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:[timeComponents hour]];
[dateComps setMinute:[timeComponents minute]];
[dateComps setSecond:00];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
[dateComps release];
appDelegate.setTimerByUser = [itemDate retain];
How i compare it with current time and date?
Thanks

Look in NSDate.h and read Apple's docs for the -compare function on NSDates.
You can do for example:
NSDate *now = [NSDate date];
NSDate *future = [now dateByAddingTimeInterval: 2 * 24 * 60 * 60]; // add two days
if ( [now compare: future] == NSOrderedAscending ) {
// now is earlier than future so we will always get here
} else {
// never reached but illustrates how you might use compare
}

I think you need NSDateComponents. You can use this class to get year, month, day, and other attributes about date and time.

NSDate * now = [NSDate date];
NSDate * twoDaysFromNow = [now dateByAddingTimeInterval:(2 * 24* 60 * 60)];
You can compare with NSDate's -earlierDate: or -laterDate: methods.

Related

sethours in NSDateComponents

I'm trying to sethours in NSDateComponents, I wrote the following code
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:intDay];
[dateComps setMonth:intMonth];
[dateComps setYear:intYear];
[dateComps setHour:intHoures];
[dateComps setMinute:intMinutes];
NSDate *itemDate;
itemDate = [calendar dateFromComponents:dateComps];
NSLog(#"reminder date: %#", itemDate);
but when I set the hours as 13, it sets it as 11. I want hours in 24 style. Anyone can help me in this issue?
Thanks in Advance.
Time difference in the hours indicate that you might have problem with time zone, you could try to set the timezone for the date, I know NSDateFormatter has timeZone Property,I doubt if NSDateComponents have timeZone property. However you could set the timeZone for calendar
[calendar setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];

Get the first day and last day of a week

I am using this method to get the current week first and last days:
NSDate *weekDate = [NSDate date];
NSCalendar *myCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *currentComps = [myCalendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekOfYearCalendarUnit | NSWeekdayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:weekDate];
int ff = currentComps.weekOfYear;
NSLog(#"1 %d", ff);
[currentComps setWeekday:1]; // 1: sunday
NSDate *firstDayOfTheWeek = [myCalendar dateFromComponents:currentComps];
[currentComps setWeekday:7]; // 7: saturday
NSDate *lastDayOfTheWeek = [myCalendar dateFromComponents:currentComps];
NSDateFormatter *myDateFormatter = [[NSDateFormatter alloc] init];
myDateFormatter.dateFormat = #"dd/MM/yyyy";
NSString *firstStr = [myDateFormatter stringFromDate:firstDayOfTheWeek];
NSString *secondStr = [myDateFormatter stringFromDate:lastDayOfTheWeek];
NSLog(#"first - %# \nlast - %#", firstStr, secondStr);
And i want to know what i should change in this to get the next week first and last day and two weeks from now to?
To get the next week, add 7 days to firstDayOfTheWeek and then lastDayOfTheWeek.
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:7];
NSDate *firstDayOfNextWeek = [myCalendar dateByAddingComponents:comps toDate:firstDayOfTheWeek options:0];
This code assumes a 7-day week. Ideally you would replace this assumption with code that gets the actual length of the week.
Side Note: Your code assume the week starts on Sunday. Many locales start their week on others days such as Monday. Change:
[currentComps setWeekday:1];
to:
[currentComps setWeekday:[myCalendar firstWeekday]];
I would then change your calculation of lastDayOfTheWeek to simply add 6 days to firstDayOfWeek.
Use Below code which returns index of current current weekly days. For example if its today is saturday than it will give you 7 means last day of week.
-(int)currentdayweeklynumber{
NSDate *CurrentDate = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];// you can use your format.
//Week Start Date
NSCalendar *gregorian = [[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorian components:NSWeekdayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:CurrentDate];
int dayofweek = [[[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate:CurrentDate] weekday];
NSLog(#" dayofweek=%d",dayofweek);
return dayofweek;
}
Using this number you add or subtract to get first or last of week. You can also use this get next week start and end date by just simple calculation.

set datepicker at a specific time

Hi guys i have a problem
i my code i set a datepicker with the date of today, after that if the user change the picker i set a alarm to ring at the date of picker.
How can i "block the picker" on these date?
here my code, i hope in your help
NSDate *pickerDate = [NSDate date];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
// Divisione della data in fattori
NSDateComponents *dateComponents = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:pickerDate];
NSDateComponents *timeComponents = [calendar components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:pickerDate];
// Set Up dell'alarme considerando tutti i fattori
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:[timeComponents hour]];
[dateComps setMinute:[timeComponents minute]];
//Notifica in meno di un minuto
[dateComps setSecond:0];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
[dateComps release];
[alarmDatePickerUno setDate:itemDate animated:YES];
[alarmDatePickerDue setDate:itemDate animated:YES];
}
// ALARM UNO
// Set Allarme Uno
-(IBAction)setAlarmUno:(id)sender{
NSLog(#"picker in allarme");
NSCalendar *currentCalendar = [NSCalendar currentCalendar];
//Setting dell'allarme in base al picker
AlarmDateUno = [alarmDatePickerUno date];
NSLog(#"allarme settata alle");
NSLog(#"%#", AlarmDateUno);
alarmDatePickerUno.userInteractionEnabled = NO;
alarmDatePickerDue.userInteractionEnabled = NO;
EDIT AFTER CLARIFICATION
If you want to use a date between app launches, you need to persist the date somehow. I would suggest using NSUserDefaults, but you could also go for the more complicated solution of Core Data. Using NSUserDefaults you would check every time you create your UIDatePicker for the saved value and use that to initialize the picker.
// Get the date
NSDate *unoDate = [[NSUserDefaults standardUserDefaults] objectForKey:#"PickerUnoKey"];
if (unoDate) { // If we have a persisted date, we set the date of the datePicker
[alarmDatePickerUno setDate:unoDate animated:NO];
}
Then when the user changes the value of the picker, you need to store the new value.
// When the datePicker value has changed, we store the value
[[NSUserDefaults standardUserDefaults] setObject:alarmDatePickerUno.date forKey:#"PickerUnoKey"];

iPhone: method to calculate days till next birthday not accurate --?

Here's a puzzler. I use the following to calculate the number of days between today's date and an upcoming birthday:
-(int) daysTillBirthday: (NSDate*)aDate {
// check to see if valid date was passed in
//NSLog(#"aDate passed in is %#",aDate);
if (aDate == nil) {
//NSLog(#"aDate is NULL");
return -1; // return a negative so won't be picked in table
}
//** HOW MANY DAYS TO BDAY
NSDate *birthDay = aDate; // [calendar dateFromComponents:myBirthDay];
//NSLog(#"birthDay: %#, today: %#",birthDay, [NSDate date]);
NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDateComponents *thisYearComponents = [calendar components:NSYearCalendarUnit fromDate:[NSDate date]];
NSDateComponents *birthDayComponents = [calendar components:NSMonthCalendarUnit|NSDayCalendarUnit fromDate:birthDay];
[birthDayComponents setYear:[thisYearComponents year]];
NSDate *birthDayThisYear = [calendar dateFromComponents:birthDayComponents];
//NSLog(#"birthDayThisYear: %#",birthDayThisYear);
NSDateComponents *differenceHours = [calendar components:NSHourCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];
NSDateComponents *differenceDays = [calendar components:NSDayCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];
// NSLog(#"difference days: %i, hours %i",[differenceDays day],[differenceHours hour]);
//*** I added this to try and correct the "error" ***
if ([differenceDays day] == 0) { // is it today, or tomorrow?
if (([differenceHours hour] <= 0) && ([differenceHours hour] >= -24)) { // must be today
//NSLog(#"TODAY");
return (0);
[calendar release];
}else if (([differenceHours hour] >= 0) && ([differenceHours hour] <= 24)) {
//NSLog(#"TOMORROW");
return (1);
[calendar release];
}
}
if ([differenceDays day] < 0) {
// this years birthday is already over. calculate distance to next years birthday
[birthDayComponents setYear:[thisYearComponents year]+1];
birthDayThisYear = [calendar dateFromComponents:birthDayComponents];
differenceDays = [calendar components:NSDayCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];
}
return ([differenceDays day]);
[calendar release];
}
Everything works, but the results are not accurate! I often find that birthdays that are close to today, but one day apart, result in [differenceDays day] being the same! i.e. if today is 6/6/2011 and I have two birthdays, one on 6/7/2011 and another 6/8/2011, then they are both shown as 1 day away!
Anyone have any better methods for accurately calculating this, or can spot the problem?
Many thanks.
NSCalendar provides a much easier way to do this:
NSDate *birthday = ...; // the birthday
NSDate *today = [NSDate date];
NSCalendar *c = [NSCalendar currentCalendar];
NSInteger birthdayDayOfYear = [c ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:birthday];
NSInteger todayDayOfYear = [c ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:today];
NSInteger different = birthdayDayOfYear - todayDayOfYear;
Basically, we're figuring out how far into the year today and the target date are (ie, today [5 Jun] is the 156th day of the year), and then subtract them to figure out how many days are in between them.
This method, of course, relies on the assumption that the target date is in the same year as the current date. I think it'd be fairly easy to work around that, however.
Another, even easier way to do this that will account for multi-year differences is like this:
NSDateComponents *d = [[NSCalendar currentCalendar] components:NSDayCalendarUnit fromDate:today toDate:birthday options:0];
NSInteger difference = [d day];
If you need to make sure that the birthday is in the future, that's easily accomplished as well:
NSDateComponents *year = [[[NSDateComponents alloc] init] autorelease];
NSInteger yearDiff = 1;
NSDate *newBirthday = birthday;
while([newBirthday earlierDate:today] == newBirthday) {
[year setYear:yearDiff++];
newBirthday = [[NSCalendar currentCalendar] dateByAddingComponents:year toDate:birthday options:0];
}
//continue on with the 2-line calculation above, using "newBirthday" instead.
update I updated the loop above to always increment from the original date n years at a time, instead of year-by-year. If someone is born on 29 Feb, incrementing by one year would yield 1 Mar, which would be wrong once you got to a leap year again. By jumping from the original date each time, we don't have this issue.
I do the exact same thing in one of my apps. Here is how I do it:
//This is the date your going to - in your case the birthday - note the format
NSString *myDateAsAStringValue = #"20110605";
// Convert string to date object
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyyMMdd"];
NSDate *newDate = [dateFormat dateFromString:myDateAsAStringValue];
NSDateComponents *dateComp = [[NSDateComponents alloc] init];
NSCalendar *Calander = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps=[[NSDateComponents alloc] init];
unsigned int unitFlags = NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
dateComp = [Calander components:unitFlags fromDate:[NSDate date]];
[dateFormat setDateFormat:#"dd"];
[comps setDay:[[dateFormat stringFromDate:[NSDate date]] intValue]];
[dateFormat setDateFormat:#"MM"];
[comps setMonth:[[dateFormat stringFromDate:[NSDate date]] intValue]];
[dateFormat setDateFormat:#"yyyy"];
[comps setYear:[[dateFormat stringFromDate:[NSDate date]] intValue]];
[dateFormat setDateFormat:#"HH"];
[comps setHour:05];
[dateFormat setDateFormat:#"mm"];
[comps setMinute:30];
NSDate *currentDate=[Calander dateFromComponents:comps];
dateComp = [Calander components:unitFlags fromDate:newDate];
[dateFormat setDateFormat:#"dd"];
[comps setDay:[[dateFormat stringFromDate:newDate] intValue]];
[dateFormat setDateFormat:#"MM"];
[comps setMonth:[[dateFormat stringFromDate:newDate] intValue]];
[dateFormat setDateFormat:#"yyyy"];
[comps setYear:[[dateFormat stringFromDate:newDate] intValue]];
[dateFormat setDateFormat:#"HH"];
[comps setHour:05];
[dateFormat setDateFormat:#"mm"];
[comps setMinute:30];
NSDate *reminderDate=[Calander dateFromComponents:comps];
NSTimeInterval ti = [reminderDate timeIntervalSinceDate:currentDate];
int days = ti/86400;
return days;
I think I have found a solution. Checking the output carefully, it appears to all come down to the difference in HOURS. For example: comparing today with tomorrow's date might end up being, say, 18 hours away. This results in [difference day] being set at 0 i.e. it thinks tomorrow is today because it is less than 24 hours away.
You can see the fix below. I take the number of hours e.g. 18 and divide by 24 (to get the number of days). In this case 18/24 = 0.75. I then round this up i.e. to "1." So while [difference days] thinks tomorrow is today, by rounding up the hours, you know it is in fact tomorrow.
-(int) daysTillBirthday: (NSDate*)aDate {
// check to see if valid date was passed in
//NSLog(#"aDate passed in is %#",aDate);
if (aDate == nil) {
//NSLog(#"aDate is NULL");
return -1; // return a negative so won't be picked in table
}
//** HOW MANY DAYS TO BDAY
NSDate *birthDay = aDate; // [calendar dateFromComponents:myBirthDay];
NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDateComponents *thisYearComponents = [calendar components:NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit fromDate:[NSDate date]];
NSDateComponents *birthDayComponents = [calendar components:NSMonthCalendarUnit|NSDayCalendarUnit fromDate:birthDay];
NSInteger timeNow = [thisYearComponents hour];
[birthDayComponents setYear:[thisYearComponents year]];
[birthDayComponents setHour:timeNow];
NSDate *birthDayThisYear = [calendar dateFromComponents:birthDayComponents];
//NSLog(#"today %#, birthday %#",[NSDate date],birthDayThisYear);
NSDateComponents *difference = [calendar components:NSDayCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];
NSDateComponents *differenceHours = [calendar components:NSHourCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];
double daysFromHours = ((double)[differenceHours hour])/24; // calculate number of days from hours (and round up)
int roundedDaysFromHours = ceil(daysFromHours);
NSLog(#"daysFromHours %.02f, roundedDaysFromHours %i",daysFromHours,roundedDaysFromHours);
if ([difference day] < 0) {
// this years birthday is already over. calculate distance to next years birthday
[birthDayComponents setYear:[thisYearComponents year]+1];
birthDayThisYear = [calendar dateFromComponents:birthDayComponents];
difference = [calendar components:NSDayCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];
}
//NSLog(#"%i days until birthday", [difference day]);
return (roundedDaysFromHours);
[calendar release];
}

Core Data - Predicates with NSDates

Hallo,
I am working on a Core Data app and have to do some filtering based on dates. I've run some testing and it appears that when comparing NSDates, Core Data is comparing the time component of the dates as well.
My code:
- (BOOL)hasSpeakersWithinDateRangeFrom:(NSDate *)startOfRange through:(NSDate *)endOfRange {
NSPredicate* dateRangePredicate = [NSPredicate predicateWithFormat:#"startOn <= %# && endOn >= %#", startOfRange, endOfRange];
NSSet* speakersWithinDateRange = [self.speakers filteredSetUsingPredicate:dateRangePredicate];
if ([speakersWithinDateRange count] > 0)
return YES;
else
return NO;
}
and I have a "convenience" method that is a one-line'er:
- (BOOL)hasSpeakersNow {
return [self hasSpeakersWithinDateRangeFrom:[NSDate date] through:[NSDate date]];
}
When I run some basic testing, it doesn't work as planned, and from what I can tell Core Data is comparing the time components of the NSDate objects along with the dates.
So, how can I rewrite the above to ignore time and only be sensitive to the day passed?
Thank you
You might want to get familiar with NSDateComponents and NSCalendar. What you will probably need to do is extract the components from your date and construct new NSDates using only the day, month, and year components without time components.
For the "current" day, you'll want to create a 1 day range by using today's date at midnight, and the date by adding 1 day to that. NSCalendar has methods to do some of this for you.
These docs might help:
NSCalendar Class Reference
NSDateComponents Class Reference
Date and Time Programming Guide
This is essentially the same as vikingosegundo, but both functions use the same method, and I personally prefer it for my use.
- (NSDate *)dateByMovingToBeginningOfDay
{
unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents* parts = [[NSCalendar currentCalendar] components:flags fromDate:self];
[parts setHour:0];
[parts setMinute:0];
[parts setSecond:0];
return [[NSCalendar currentCalendar] dateFromComponents:parts];
}
- (NSDate *)dateByMovingToEndOfDay
{
unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents* parts = [[NSCalendar currentCalendar] components:flags fromDate:self];
[parts setHour:23];
[parts setMinute:59];
[parts setSecond:59];
return [[NSCalendar currentCalendar] dateFromComponents:parts];
}
Set the startDate to time 0:00:00 and the endDate to 23:59:59
NSDate *startDate = [NSDate date]; //Now
startDate= [date dateAtMidnight]; //today at 0:00
NSDate *endDate = [NSDate date];
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:#"gregorian"];
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:1];
[comps setSecond:-1]
endDate = [cal dateByAddingComponents:comps toDate:endDate options:0];//today 23:59:59
edit
this solution uses NSDate-Category NSDateAdditions.h, provided by Three20 (I wasnt aware it isn't defined in Cocoa)
- (NSDate*)dateAtMidnight {
NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"yyyy-d-M";
NSString* formattedTime = [formatter stringFromDate:self];
NSDate* date = [formatter dateFromString:formattedTime];
[formatter release];
return date;
}