I have a picker view similar to the alarm clock app on the iphone (first component = 1-12, second component = 0-60, third component = am/pm). What I do is this in the didSelect delegate of the picker view.
if (component == PICKER_HOURS) {
rowSelected = [self.hour objectAtIndex:row % 12];
self.hourSelected = rowSelected;
}
else if (component == PICKER_MINUTES) {
rowSelected = [self.minutes objectAtIndex:row % 60];
self.minuteSelected = rowSelected;
}
else {
rowSelected = [self.ampm objectAtIndex:row];
self.ampmSelected = rowSelected;
}
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
dateFormatter.dateFormat = #"h:mm a";
NSString *timeString = [NSString stringWithFormat:#"%#:%# %#", _hourSelected, _minuteSelected, _ampmSelected];
NSString *trimmedTimeString = [timeString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
NSDate *dateSelected = [dateFormatter dateFromString:timeString];
NSDate *dateForAlarm = [self alarmDateForDate:dateSelected];
------
- (NSDate *)alarmDateForDate:(NSDate *)dateSelected {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate:[NSDate date]]; // set the date to the current date
NSDateComponents *timeComponents = [calendar components:(NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:dateSelected]; // set the time to what's in the picker
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setYear:[dateComponents year]];
[dateComps setMonth:[dateComponents month]];
[dateComps setHour:[timeComponents hour]];
[dateComps setMinute:[timeComponents minute]];
NSDate *dateForAlarm = [calendar dateFromComponents:dateComps];
return dateForAlarm;
}
Is this the right approach? I realized that my dateFromString in the picker view is always the 1970 time. So I wasn't sure if this was 'standard' way to get the time from a picker view so that it is in the future to set a notification. Thanks!
Look at this -
Date Picker :-
m_pDatePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 40, 50, 50)];
m_pDatePicker.datePickerMode = UIDatePickerModeDate;
NSDate *minDate = [NSDate new];
[m_pDatePicker setMinimumDate:minDate];
m_pDatePicker.hidden = NO;
[m_pClientView addSubview:m_pDatePicker];
[m_pDatePicker addTarget:self action:#selector(pickDateLabel)forControlEvents:UIControlEventValueChanged];
NSDateComponents* comps = [m_pDatePicker.calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate:m_pDatePicker.date];
int myDay = [comps day];
int myMonth = [comps month];
int myYear = [comps year];
pickDateLabel.text=[NSString stringWithFormat:#"%d/%d/%d",myMonth,myDay,myYear];
dueDateLabel.text=[NSString stringWithFormat:#"%d/%d/%d",myDay,myMonth,myYear];
[m_pDatePicker release];
[minDate release];
}
Picking Date -
- (void)pickDateLabel
{
NSDateComponents* comps = [m_pDatePicker.calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate:m_pDatePicker.date];
int myDay = [comps day];
int myMonth = [comps month];
int myYear = [comps year];
pickDateLabel.text=[NSString stringWithFormat:#"%d/%d/%d",myMonth,myDay,myYear];
dueDateLabel.text=[NSString stringWithFormat:#"%d/%d/%d",myDay,myMonth,myYear];
}
Hope it helps !!
Related
I'm writing an application based on UILocalNotifications. I having the user input a time on a date picker and that time will represent when the last UILocalNotification will fire. After the user hits a UIButton UILocalNotifications will fire based on a time interval until the time they selected occurs, then the app will stop.
I schedule the maximum number of UILocalNotifications before the user inputs a time. Is there a way to cancel the UILocalNotifications that are scheduled after the user's input time, based on time? Or is there a way to cancel all scheduled notifications after the inputted notification fires? The code is setting the last timer and the first timer based of the input time. Thanks for the help.
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:0];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
/**************Setting the final alarm*********************/
UILocalNotification *finalAlarm = [[UILocalNotification alloc] init];
if (finalAlarm) {
finalAlarm.fireDate = itemDate;
finalAlarm.timeZone = [NSTimeZone defaultTimeZone];
finalAlarm.repeatInterval = 0;
finalAlarm.soundName = UILocalNotificationDefaultSoundName;
finalAlarm.alertBody = #"Test message...";
[[UIApplication sharedApplication] scheduleLocalNotification:finalAlarm];
}
//Formatting original date in the date picker for readability
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH"];
NSString *formattedDateString = [dateFormatter stringFromDate:datePicker.date];
//isolate current date/time
NSDate *currentDate = [NSDate date];
//formatting the current date for readability
[dateFormatter setDateFormat:#"HH"];
NSString *currentForamttedDate = [dateFormatter stringFromDate:currentDate];
//current hour
int currentHour = [currentForamttedDate intValue];
/**************Setting the first alarm*********************/
//current hour plus 2
int firstAlarmHour = currentHour + 2;
//creating the first alarm
NSDateComponents *firstAlarm = [[NSDateComponents alloc]init];
[firstAlarm setDay:[dateComponents day]];
[firstAlarm setMonth:[dateComponents month]];
[firstAlarm setYear:[dateComponents year]];
[firstAlarm setHour:firstAlarmHour];
[firstAlarm setMinute:[dateComponents minute]];
[firstAlarm setSecond:0];
//creating a date from the components
NSDate *firstAlarmDate = [calendar dateFromComponents:firstAlarm];
//setting the first alarm
[self scheduleNotificationForDate: firstAlarmDate];
You can use the following code to get all the notifications and then cancel them based on your specifications.
if ([[UIApplication sharedApplication].scheduledLocalNotifications count] > 1){
for (int i = 0; i < [[UIApplication sharedApplication].scheduledLocalNotifications count]; i++){
UILocalNotification * notification = [[UIApplication sharedApplication].scheduledLocalNotifications objectAtIndex:i];
if (/* if after your fire date */){
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
}
I have two UIDatePickers in my app, one mode is for selecting date and other to time mode. I have fired a notification when the exact date and time is reached. I'm able to fire the reminder at correct time, but the problem is that the date is not checked. Is there any way to check the date and time at the same time??
Thanx in advance...
Edit
NSDate *date1 = [datePicker date];
NSDate *date2 = [timePicker date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
unsigned unitFlagsDate = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *dateComponents = [gregorian components:unitFlagsDate fromDate:date1];
unsigned unitFlagsTime = NSHourCalendarUnit | NSMinuteCalendarUnit ;
NSDateComponents *timeComponents = [gregorian components:unitFlagsTime fromDate:date2];
[dateComponents setHour:[timeComponents hour]];
[dateComponents setMinute:[timeComponents minute]];
NSDate *combDate = [gregorian dateFromComponents:dateComponents];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil) return;
NSDate *fireTime = combDate;
localNotif.fireDate = fireTime;
localNotif.alertBody = #"Alert!";
localNotif.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComponents = [calendar components:NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:self.datePicker.date];
NSDateComponents *timeComponents = [calendar components:NSHourCalendarUnit|NSMinuteCalendarUnit fromDate:self.timePicker.date];
NSDateComponents *newComponents = [[NSDateComponents alloc]init];
newComponents.timeZone = [NSTimeZone systemTimeZone];
[newComponents setDay:[dateComponents day]];
[newComponents setMonth:[dateComponents month]];
[newComponents setYear:[dateComponents year]];
[newComponents setHour:[timeComponents hour]];
[newComponents setMinute:[timeComponents minute]];
NSDate *combDate = [calendar dateFromComponents:newComponents];
NSLog(#" \ndate : %# \ntime : %#\ncomDate : %#",self.datePicker.date,self.timePicker.date,combDate);
Swift 5 version of the accepted answer if it might help.
/// Returns `Date` from date and time.
func combine(date: Date, time: Date) -> Date? {
let calendar = Calendar.current
let dateComponents = calendar.dateComponents([.day, .month, .year], from: date)
let timeComponents = calendar.dateComponents([.hour, .minute, .second], from: time)
var newComponents = DateComponents()
newComponents.timeZone = .current
newComponents.day = dateComponents.day
newComponents.month = dateComponents.month
newComponents.year = dateComponents.year
newComponents.hour = timeComponents.hour
newComponents.minute = timeComponents.minute
newComponents.second = timeComponents.second
return calendar.date(from: newComponents)
}
Try this:
Convert date into NSString and Time into NSString.
Apppend Time into date string.
Now convert that final string into NSDate
Example: (Add validations from ur side)
NSDate *date1 = [datePicker date];
NSDate *date2 = [timePicker date];
NSString *date = [NSString stringWithFormat:#"%#",date1];
NSString *time = [NSString stringWithFormat:#"%#",date2];
NSString *dateAndTime = [NSString stringWithFormat:#"%# %#",date,time];
NSDate *dateTime = [self dateFromString:dateAndTime];
- (NSDate*) dateFromString:(NSString*)aStr
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"] autorelease]];
//[dateFormatter setDateFormat:#"YYYY-MM-dd HH:mm:ss a"];
[dateFormatter setDateFormat:#"MM/dd/yyyy HH:mm:ss a"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSLog(#"%#", aStr);
NSDate *aDate = [dateFormatter dateFromString:aStr];
[dateFormatter release];
return aDate;
}
I want to save a reminder, but when I set the StartDateComponents, it always says Invalid date component. I try several ways(you can see my commented code) to set the value, but failed.
EKReminder *reminder = [EKReminder reminderWithEventStore:appDelete.eventStore];
NSCalendar *gregorian = [NSCalendar currentCalendar];//[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
reminder.title = #"title";
NSString *timeStr = #"20121115070800";
NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
[inputFormatter setCalendar:gregorian];
[inputFormatter setDateFormat:#"yyyyMMddHHmmss"];
[inputFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
NSDate *parseDate = [inputFormatter dateFromString:timeStr];
NSDateComponents *dateComponents = [gregorian components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:parseDate];
NSDateComponents *timeComponents = [gregorian components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:parseDate];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:[timeComponents hour]];
// Notification will fire in one minute
[dateComps setMinute:[timeComponents minute]];
[dateComps setSecond:[timeComponents second]];
[dateComps setTimeZone:[NSTimeZone localTimeZone]];
reminder.calendar = /*[NSCalendar autoupdatingCurrentCalendar];*/[eventStore defaultCalendarForNewEvents];
reminder.calendar = [EKCalendar calendarWithEventStore:eventStore];
//NSDateComponents *comp = [[NSDateComponents alloc] init];
/*comp.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
comp.year = [[timeStr substringToIndex:3] integerValue];
comp.month = [[timeStr substringWithRange:NSMakeRange(4,2)] integerValue];
comp.day = [[timeStr substringWithRange:NSMakeRange(6, 2)] integerValue];
comp.hour = [[timeStr substringWithRange:NSMakeRange(8, 2)] integerValue];
comp.minute = [[timeStr substringWithRange:NSMakeRange(10, 2)] integerValue];
comp.second = [[timeStr substringWithRange:NSMakeRange(12, 2)] integerValue];*/
//reminder.startDateComponents = [gregorian components: (NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit/*|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit*/) fromDate:parseDate];
[reminder setStartDateComponents:dateComps];// this line will throw the error:Invalid date component
It seemed the main issue was these 2 lines:
reminder.calendar = /*[NSCalendar autoupdatingCurrentCalendar];*/[eventStore defaultCalendarForNewEvents];
reminder.calendar = [EKCalendar calendarWithEventStore:eventStore];
Replace with this line:
reminder.calendar = [eventStore defaultCalendarForNewReminders];
Here are the complete working code that also included a little extra for completeness:
EKEventStore *eventStore = [[EKEventStore alloc] init];
[eventStore requestAccessToEntityType:EKEntityMaskEvent completion:^(BOOL granted, NSError *error) {
if (granted)
{
EKReminder *reminder = [EKReminder reminderWithEventStore:eventStore];
NSCalendar *gregorian = [NSCalendar currentCalendar];//[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
reminder.title = #"title44433333";
NSString *timeStr = #"20121115070800";
NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
[inputFormatter setCalendar:gregorian];
[inputFormatter setDateFormat:#"yyyyMMddHHmmss"];
[inputFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
NSDate *parseDate = [inputFormatter dateFromString:timeStr];
NSDateComponents *dateComponents = [gregorian components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit )
fromDate:parseDate];
NSDateComponents *timeComponents = [gregorian components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit )
fromDate:parseDate];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setDay:[dateComponents day]];
[dateComps setMonth:[dateComponents month]];
[dateComps setYear:[dateComponents year]];
[dateComps setHour:[timeComponents hour]];
// Notification will fire in one minute
[dateComps setMinute:[timeComponents minute]];
[dateComps setSecond:[timeComponents second]];
[dateComps setTimeZone:[NSTimeZone localTimeZone]];
reminder.calendar = [eventStore defaultCalendarForNewReminders]; //here is the replacement
[reminder setStartDateComponents:dateComps];// this line will throw the error:Invalid date component
NSError *error = nil;
[eventStore saveReminder:reminder commit:YES error:&error];
if (error) NSLog(#"error = %#", error);
}
}];
I was wondering how I would edit the dateComps setDay: to go off 3 days before the date set in the picker. I typed in -3, but that doesn't seem to do the trick.
Any help is much appreciated! Here is my code:
- (IBAction)scheduleNotifButton:(id)sender {
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:13];
[dateComps setMinute:30];
[dateComps setSecond:[timeComponents second]];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.fireDate = itemDate;
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertBody = #"Event is in 3 days!";
localNotif.alertAction = nil;
localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotif.applicationIconBadgeNumber = 0;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}
When you say you have typed -3, do you mean you used this line?
[dateComps setDay:[dateComponents day] - 3];
This should in fact work.
Also, you can tell the system to fire any next year by just settings the current year to the date components. You can find the current year just the way you found the date components for pickerDate.
After that, you can set the repeatInterval of the local notification to NSYearCalendarUnit, that way it will fire each year.
Here is a code to subtract 3 days from Today(NOW). You can adapt it for your needs:
NSDate *today = [NSDate date];
NSLog(#"NOW:%#",today);
NSCalendar *gregorian = [[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *todayComps = [gregorian components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit |NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:today];
todayComps.day -=3;
NSDate *dateMinus3Days = [gregorian dateFromComponents:todayComps];
NSLog(#"3 days before NOW:%#",dateMinus3Days);
Your making it too complicated. DateComponents can be modified and then set to a new date.
I think all you need to do is subtract 3 days from the date returned by the date picker, no?
NSDate *pickerDate = [self.datePicker date]
pickerDate = [ pickerDate dateByAddingTimeInterval:-3 * 24 * 60 * 60 ] ; // add this line
Version using date components:
- (IBAction)scheduleNotifButton:(id)sender {
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDate *pickerDate = [self.datePicker date];
{
NSDateComponent * deltaComponents = [ [ NSDateComponents alloc ] init ];
deltaComponents.days = -3 ;
pickerDate = [ pickerDate dateByAddingComponents:deltaComponents ] ;
}
NSDateComponents *dateComponents = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit ) fromDate:pickerDate];
[dateComps setHour:13];
[dateComps setMinute:30];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
if (localNotif == nil)
return;
localNotif.fireDate = itemDate;
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.alertBody = #"Event is in 3 days!";
localNotif.alertAction = nil;
localNotif.soundName = UILocalNotificationDefaultSoundName;
localNotif.applicationIconBadgeNumber = 0;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}
Use dateByAddingComponents:toDate:options:
// ...
NSDateComponents *offset = [NSDateComponents new];
[offset setDay:(-3)];
NSDate *date3DaysBefore = [calendar dateByAddingComponents:offset toDate:pickerDate options:0];
// ...
I want to make an NSDate object which has the date set as the current date, but the time set as the time in the datepicker (because the datepicker's mode is the time one). How can i do this?
and if you really want to use a custom date use something like this.
- (IBAction)dpChange:(UIDatePicker *)sender {
// replace this with your custom date.
NSDate *myCustomDate = [NSDate dateWithTimeIntervalSinceNow:7*24*60*60];
NSInteger dateFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:dateFlags fromDate:myCustomDate];
NSDate *myCustomTime = [sender date];
NSInteger timeFlags = NSHourCalendarUnit | NSMinuteCalendarUnit;
NSDateComponents *timeComponents = [[NSCalendar currentCalendar] components:timeFlags fromDate:myCustomTime];
NSDateComponents *newComponents = [[[NSDateComponents alloc] init] autorelease];
[newComponents setYear:[dateComponents year]];
[newComponents setMonth:[dateComponents month]];
[newComponents setDay:[dateComponents day]];
[newComponents setHour:[timeComponents hour]];
[newComponents setMinute:[timeComponents minute]];
[newComponents setSecond:0];
NSDate *newDate = [[NSCalendar currentCalendar] dateFromComponents:newComponents];
NSLog(#" Date: %#", myCustomDate);
NSLog(#" Time: %#", myCustomTime);
NSLog(#"Combined: %#", newDate);
}