I have a method that makes the store of a UILocalNotification:
- (void)save:(NSString *)program at:(NSDate*)date {
NSLog(#"date to save: %#", date);
// NSLog(#"timezone: %#",[date descriptionWithLocale:[NSLocale systemLocale]]);
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
NSLog(#"date to fire: %#", date);
localNotification.fireDate = date;
NSString *s=[program stringByAppendingString:#" is now on "];
NSString *title=[s stringByAppendingString:channel];
localNotification.alertBody = title;
localNotification.alertAction = #"Show...";
//localNotification.timeZone = [NSTimeZone localTimeZone];
localNotification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
NSLog(#"notification to save %#",localNotification);
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
// Request to reload table view data
[[NSNotificationCenter defaultCenter] postNotificationName:#"reloadData" object:self];
// Dismiss the view controller
[self dismissViewControllerAnimated:YES completion:nil];
}
And I have as output:
date to save: 2013-08-29 17:00:00 +0000
date to fire: 2013-08-29 17:00:00 +0000
notification to save <UIConcreteLocalNotification: 0xc0c4240>{fire date = Thursday, August 29, 2013, 6:00:00 PM Central European Standard Time, time zone = (null), repeat interval = 0, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Thursday, August 29, 2013, 6:00:00 PM Central European Standard Time, user info = (null)}
Despite uncommenting the timezone setting, the UILocalNotification is always incrementing by one hour, why, and how ?
Thank you for helping.
The date you pass in in GMT, which in you case is does not match your local time zone.
So when you set the date to 17:00 your time corrects it to you timezone (CET) which is GMT+1.
Thus an hour gets added to you date.
A solution is to set the UILocalNotification timezone to GMT:
localNotification.timeZone = [NSTimeZone timeZoneWithName#"GMT"];
From the Apple documentation:
The date specified in fireDate is interpreted according to the value
of this property. If you specify nil (the default), the fire date is
interpreted as an absolute GMT time, which is suitable for cases such
as countdown timers. If you assign a valid NSTimeZone object to this
property, the fire date is interpreted as a wall-clock time that is
automatically adjusted when there are changes in time zones; an
example suitable for this case is an an alarm clock.
Related
I have a NSString (ex. "2011-04-12 19:23:39"), and what I did to format it to a NSDate was the following:
[inputFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *date = [inputFormatter dateFromString:newDateString];
but what it outputs when I nslog the date is this:
2011-04-12 23:23:39 +0000
which is about 4 hours off. Is there something I missed? Possibly a time zone problem?
The answer in short, is the Date is being returned GMT unless specified otherwise. You can set your timezone to get the correct date. If you plan on using the date in the app to set anything ( like localNotification time or Event ) you will need to do something special with the date because if you set the date in the iPhone it will be set as GMT time and will be off by a few hours. ( in your case 4 hours ). I do this exact thing I just described in one of my apps.
I made a mess of trying to get this to work correctly without having the hours be off. It was a huge PITA to figure out but its working now. I have copied, pasted, and edited my code to share. Again, its messy but it works! The pickerChanged is getting its info from a UIDatePicker
Using the code below. To answer your question, you can stop at "destinationDate". That will return to you the corrected time for your current time zone. I just provided the extra incase you were trying to use the date in the Phone somewhere.
NOTE: for a quick example i put the Event reminder in the same function as the datepicker, you will NOT want to do that otherwise you will have alot of reminders set everytime the wheel scrolls in the datepicker.
The code is below.
- (void)pickerChanged:(id)sender
{
NSLog(#"value: %#",[sender date]);
NSDate* date= [sender date];
NSDateFormatter *formatter=[[[NSDateFormatter alloc]init]autorelease];
[formatter setDateFormat:#"MM/dd/yyyy hh:mm:ss a"];
[formatter setTimeZone:[NSTimeZone systemTimeZone]];
[formatter setTimeStyle:NSDateFormatterLongStyle];
NSString *dateSelected =[formatter stringFromDate:date];
NSString *timeZone = [dateSelected substringFromIndex:12];
NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];
//here we have to get the time difference between GMT and the current users Date (its in seconds)
NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:date];
//need to reverse offset so its correct when we put it in the calendar
correctedTimeForCalendarEvent = destinationGMTOffset + (2*(-1*destinationGMTOffset));
//date to enter into calendar (we will use the correctedTimeForCalendarEvent to correct the time otherwise it will be off by a few hours )
NSDate * destinationDate = [[[NSDate alloc] initWithTimeInterval:destinationGMTOffset sinceDate:date] autorelease];
NSDate * dateForReminder = destinationDate;
// return destinationDate;
NSLog(#"value: %# - %#",destinationDate,dateForReminder);
//DO NOT put this code in this same function this is for a quick example only on StackOverflow
//otherwise you will have reminders set everytime the users scrolled to a different time
//set event reminder
//make sure to import EventKit framework
EKEventStore *eventDB = [[[EKEventStore alloc] init]autorelease];
EKEvent *myEvent = [EKEvent eventWithEventStore:eventDB];
NSString * eventTitle = [NSString stringWithFormat:#"%# - %#",app.dealerBusinessName,serviceOrComments.text];
myEvent.title = eventTitle;
//double check date one more time
NSLog(#"value: %#",destinationDate);
//set event time frame (1 hour) the "initWithTimeInterval" is where we account for the users timezone by adding the correctedTime from GMT to the calendar time ( so its not off by hours when entering into calendar)
myEvent.startDate = [[[NSDate alloc] initWithTimeInterval:correctedTimeForCalendarEvent sinceDate:destinationDate ]autorelease];
myEvent.endDate = [[[NSDate alloc] initWithTimeInterval:3600 sinceDate:myEvent.startDate]autorelease];
myEvent.allDay = NO;
//set event reminders 1 day and 1 hour before
myAlarmsArray = [[[NSMutableArray alloc] init] autorelease];
EKAlarm *alarm1 = [EKAlarm alarmWithRelativeOffset:-3600]; // 1 Hour
EKAlarm *alarm2 = [EKAlarm alarmWithRelativeOffset:-86400]; // 1 Day
[myAlarmsArray addObject:alarm1];
[myAlarmsArray addObject:alarm2];
myEvent.alarms = myAlarmsArray;
[myEvent setCalendar:[eventDB defaultCalendarForNewEvents]];
NSError *err;
[eventDB saveEvent:myEvent span:EKSpanThisEvent error:&err];
if (err == noErr) {
//no error, but do not show alert because we do that below.
}
}
NSDateFormatter use the current device timezone when it created the NSDate object. NSDate stores the date/time in GMT. Therefore by default NSLog will output the date/time in GMT+0. So, there's nothing wrong with your code. Now if you want to output the NSDate to your current timezone, your will have to use a NSDateFormatter object.
Your data and date formatter omit the TimeZone specifier. So something like this:
[inputFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ssZ"];
Would work - the Z is the timezone specifier and will parse both numeric offsets and timezone codes. Although in your case as your input date has no TimeZone information it won't work.
Your correct Time string should be like "2011-04-12 19:23:39 -0400" or "2011-04-12 19:23:39 EST "
Depending on where you get your date from, you should fix that to produce a fully qualified date if you can't do that, you will have to agree timezone offsets with the server or simply 'hard code' a timezone offset and add that number of seconds to your NSDate.
The date is being logged as a UTC date can be seen by the +0000 at the end. The date format you are using to parse the string assumes your local time zone which is presumably 4 hours behind UTC with daylight savings and the standard -5 hours.
Use -[NSDateFormatter setTimeZone:] to provide the date formatter with timezone information. You can use the local time zone, or if you have a fixed time zone associated with the date information, I recommend creating the timezone with the name (such as "America/East") rather than the abbreviation (such as "EST" or "EDT"), since the name does not force daylight savings into effect, but uses the correct daylight savings offset for that date in that timezone.
I'm having trouble converting NSDate date to local DateTime. I'm using Local Notifications and my fireDate property is ok except UTC component in my date.
This is NSDate date and converted date to my local timezone
This is my conversion code as found here Convert UTC NSDate to local Timezone Objective-C
NSDate *someDateInUTC = [NSDate date];
NSTimeInterval timeZoneSeconds = [[NSTimeZone localTimeZone] secondsFromGMT];
NSDate *dateInLocalTimezone = [someDateInUTC dateByAddingTimeInterval:timeZoneSeconds];
I'm adding five seconds to my time component so this is my fireDate:
I'm using push notifications and when the user is somewhere in the app, I want to present him local notification from my push notification. This code is in my - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo method. I've implemented method for local notifications:
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
UIApplicationState applicationState = application.applicationState;
if (applicationState == UIApplicationStateBackground) {
[application presentLocalNotificationNow:notification];
}
}
I'm thinking that this UTC component in my dateInLocalTimezone is causing my trouble but I don't know how to solve it.
Ok so i read your question. and i have then below example for you.
here i am converting Local time to UTC Time.
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = #"LLL d, yyyy - HH:mm:ss zzz";
NSDate *utc = [fmt dateFromString:#"June 14, 2012 - 01:00:00 UTC"];
fmt.timeZone = [NSTimeZone systemTimeZone];
NSString *local = [fmt stringFromDate:utc];
NSLog(#"%#", local);
I set the repeatInterval of my notification to NSYearCalendarUnit.
When I received the notification, I see this notification information that I log:
fire date = Tuesday, 13 May, 2014... next fire date = Wednesday, 13 May, 2015
Then I cancel the notification thinking that it will move the fire date to May 13 2015
[application cancelLocalNotification:locationNotification];
but it didn't... It really cancels the notification.
But when I didn't cancel the notification, the notification is retained however my fire date remains the same, I want it to move to 2015 and the next fire date to move to 2016
fire date = Tuesday, 13 May, 2014... next fire date = Wednesday, 13 May, 2015
You should update the fire date of the notification.
Try with this:
// Maybe in your code you don't need this, but I write it anyway
[application cancelLocalNotification:locationNotification];
// This will create a new date one year past the current notification fire date
NSDateComponents * components = [[NSDateComponents alloc] init];
components.year = 1;
NSDate * newDate = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:localNotification.fireDate options:kNilOptions];
// Now you can update the localNotification fire date
localNotification.fireDate = newDate;
// Schedule it. Again, maybe you don't need this in your code
[application scheduleLocalNotification:localNotification];
I have a date from date picker in ios, I get the date and the time and I convert this to string and saved in localStorage. Then, I get this string date and convert it to NSDate and use it in my notification. But my problem is that the notification are not run because the date changes after conversion.
The time and date from picker is: dateFromPicker=Thursday-20-March-2014 09:21 AM
The time and date from picker before 4 hours is :StringDateBefore4hours=Thursday-20-March-2014 05:21 AM
The string time before 4 hours after converting to NSDate is :DateBefore4hours=2014-03-20 00:21:00 +0000
The time is changed and my notification not run on the time selected what can we do help me please please .
That is code for getting date from picker and assigning to notification
NSDate *date=[self.DatePicker date];
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = date;
localNotification.alertBody = self.TextField.text;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.applicationIconBadgeNumber=[[UIApplication sharedApplication]applicationIconBadgeNumber]+1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
I am trying to get my app to fire a notification based off a scheduled event. The date given is from a schedule that will take place in EST. The time given is Fri Feb 21 2014 12:00:00 -0500 (Noon EST).
When the button to schedule a notification is pressed, it runs this code:
NSString *message = [#"15 minutes until " stringByAppendingString:self.thetitle];
NSLog(#"original%#", self.thedate);
NSDate *newDate = [self.thedate dateByAddingTimeInterval:-60*15];
NSDateFormatter *formatter3 = [[NSDateFormatter alloc] init];
// [formatter3 setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
[formatter3 setTimeStyle:NSDateFormatterShortStyle];
[formatter3 setDateStyle:NSDateFormatterShortStyle];
NSString *detailstext = [formatter3 stringFromDate:newDate];
NSDate *othernewdate = [formatter3 dateFromString:detailstext];
NSLog(#"other%#", othernewdate);
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.timeZone = [NSTimeZone systemTimeZone];
notification.fireDate = othernewdate;
notification.alertBody = message;
notification.soundName = UILocalNotificationDefaultSoundName;
notification.hasAction = YES;
notification.alertAction = NSLocalizedString(#"View", #"View notification button");
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
Since the time being set on the notification fireDate is the othernewdate, I ran an NSLog in the console to see what it showed. It came back:
2014-02-21 16:45:00 +0000
This seems to be perfect, because that time in EST would be 11:45 AM, or 15 minutes before noon, which is what I wanted.
The issue is this:
I am testing this in CST. I run the app, tell it to schedule a notification for this event, and then change my phone clock to be EST and it ends up firing the notification at 10:45.
There will be people using this app from different time zones, and then traveling to EST for when the conference that this app is for starts. I don't want them to schedule lots of notifications while in a different time zone and have it fire at the wrong time. Any suggestions?
If you want the notification to fire at an absolute date/time, independent of the time zone, then you must set notification.timezone = nil.
From the documentation:
"The date specified in fireDate is interpreted according to the value of this property. If you specify nil (the default), the fire date is interpreted as an absolute GMT time, which is suitable for cases such as countdown timers. If you assign a valid NSTimeZone object to this property, the fire date is interpreted as a wall-clock time that is automatically adjusted when there are changes in time zones; an example suitable for this case is an an alarm clock."