Understanding UILocalNotification timeZone
I just ran some tests on iOS 6.1.3. Here's what I got:
I'm in Seattle, at 1:00PM (Pacific Daylight Time, GMT-7). I created a NSDate
:
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
// 2013-08-31 @ 12:00:00 (noon)
dateComponents.year = 2013;
dateComponents.month = 8;
dateComponents.day = 31;
dateComponents.hour = 12;
dateComponents.minute = 0;
dateComponents.second = 0;
NSDate *fireDate = [gregorianCalendar dateFromComponents:dateComponents];
now I have
fireDate = 2013-08-31 19:00:00 +0000 (2013-08-31 12:00:00 -0700)
Then I created and scheduled the notifications:
notification1 = [[UILocalNotification alloc] init];
notification1.fireDate = fireDate;
// notification1.timeZone is nil by default
NSLog(@"%@", notification1);
notification2 = [[UILocalNotification alloc] init];
notification2.fireDate = fireDate;
notification2.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
NSLog(@"%@", notification2);
notification3 = [[UILocalNotification alloc] init];
notification3.fireDate = fireDate;
notification3.timeZone = [NSTimeZone defaultTimeZone];
NSLog(@"%@", notification3);
Logs of the notifications just created, in Seattle (Pacific Daylight Time, GMT-7):
notification1:
fire date = Saturday, August 31, 2013, 12:00:00 PM Pacific Daylight Time,
time zone = (null),
next fire date = Saturday, August 31, 2013, 12:00:00 PM Pacific Daylight Time
notification2:
fire date = Saturday, August 31, 2013, 7:00:00 PM GMT,
time zone = GMT (GMT) offset 0,
next fire date = Saturday, August 31, 2013, 7:00:00 PM Pacific Daylight Time
notification3:
fire date = Saturday, August 31, 2013, 12:00:00 PM Pacific Daylight Time,
time zone = US/Pacific (PDT) offset -25200 (Daylight),
next fire date = Saturday, August 31, 2013, 12:00:00 PM Pacific Daylight Time
I changed the phone's timezone to Chicago, where now it is 3:00PM (Central Daylight Time, GMT-5).
Logs of the notifications, in Chicago (Central Daylight Time, GMT-5)
notification1:
fire date = Saturday, August 31, 2013, 2:00:00 PM Central Daylight Time,
time zone = (null),
next fire date = Saturday, August 31, 2013, 2:00:00 PM Central Daylight Time
notification2:
fire date = Saturday, August 31, 2013, 7:00:00 PM GMT,
time zone = GMT (GMT) offset 0,
next fire date = Saturday, August 31, 2013, 7:00:00 PM Central Daylight Time
notification3:
fire date = Saturday, August 31, 2013, 12:00:00 PM Pacific Daylight Time,
time zone = US/Pacific (PDT) offset -25200 (Daylight),
next fire date = Saturday, August 31, 2013, 12:00:00 PM Central Daylight Time
Conclusions:
- When UILocalNotification
timeZone
is nil, the fire date is fixed in time. That means the notification will be fired at 12:00PM GMT-7, 2:00PM GMT-5, or 7:00 GMT. - When UILocalNotification
timeZone
is set to GMT, the fire date is calculated for GMT time and will auto-update if the user goes to another time zone. In this example, the time 12:00 GMT-7 was converted to 19:00 GMT, and the notification was set to 19:00 local time, whatever time zone we are (19:00 GMT, 19:00 GMT-5 or 19:00 GMT-7). - When UILocalNotification
timeZone
is set to the local time zone (Pacific Daylight Time, GMT-7), the fire date is calculated for the local time and will auto-update if the user goes to another time zone. In this example, the time was 12:00 GMT-7, so the notification will be fired at 12:00 local time, whatever time zone we are (12:00 GMT, 12:00 GMT-5 or 12:00 GMT-7).
UILocalNotification always setting the date to local timezone
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.
Notification Center and changing timezones
So, I managed to make it work. The triggerDate
has a timeZone variable which is automatically nil, exactly like UILocalNotification
.
triggerDate.timeZone
behaves exactly like UILocalNotification.timeZone
(behaviour described in this post, the same as mentioned in the question).
One of the reason it did not seem to work on the simulator was because I was not restarting the simulator when changing the timezone. Restarting will make everything work as expected.
Nota bene: Maybe a restart is not mandatory but since it's not obvious how much time a running simulator will take to detect the new timezone, I think restarting it is the most efficient solution.
UILocalNotification - Fire at 6:00am in every time zone
I think I've manage to figure it out.
UILocalNotification *localNotification;
[localNotification setTimeZone:[NSTimeZone localTimeZone]];
[localNotification setFireDate:fireDate];
This will make whatever Date is in fireDate the time/Date that the notification will go off, in the user's current timezone. So it will go off at 6:00am in Sydney, then again at 6:00am in Los Angeles, etc.
So that part was working as intended, where I had made the mistake was in displaying the time.
Instead of the code in my question I needed to set the timeZone of the NSDateFormatter to the timeZone of the UILocalNotification:
UILocalNotification *myLN = <The UILocalNotification we've retrieved from somewhere>;
NSDateFormatter* df_local = [[[NSDateFormatter alloc] init] autorelease];
[df_local setTimeZone:myLN.timeZone];
[df_local setDateFormat:@"hh:mm"];
NSString* ts_local_string = [df_local stringFromDate:fd];
Local notifications not adjusting for timezones
See the documentation of the timeZone
property of UILocalNotification
:
... 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.
So I assume that if you want an absolute time for the notification, you must not assign a time zone.
Swift 3 Local Notifications - Setting Automatic Timezone
autoupdatingCurrent
!=autoupdatingCurrent
NSTimeZone
has been renamed toTimeZone
Related Topics
Invalid Signature - Code Object Is Not Signed at All
Randomly Choosing an Item from a Swift Array Without Repeating
Macos on Vmware Doesn't Recognize iOS Device
Change Uitextfield and Uitextview Cursor/Caret Color
How to Make a Call Which Begin with * in Iphone
Cast Value of Type 'Uitableviewcell' to Custom Cell
Repeat Interval for Unnotification
What Privacy-Violating or Device-Changing Things How to Do on an Iphone
Sending Data from One Viewcontroller to Another
How to Make a Swiftui Gesture That Keeps Running Code While the View Is Pressed
How to Force My Keyboard to Be Up on My Program's Start in Swift
How to Use Device Instead of Simulator
No Such File and Directory Found Xcode 7
How to Fetch User's Email Using Facebook
"File Not Found", "Linker Command Failed with Exit Code 1" in Xcode 4.5.1
How to Add Constraint Between a View and the Top Layout Guide in a Xib File
Swift 3 How to Get Date for Tomorrow and Yesterday ( Take Care Special Case ) New Month or New Year
Avplayer Stalling on Large Video Files Using Resource Loader Delegate