I have a strange problem with EKEventEditViewController when using it with custom timezones. It behaves differently in two situations:
Situation 1 - works fine:
Launch app
Create EKEventEditViewController to add new event with startDate = [NSDate date]
New event start is displayed correctly (current time)
Change default timezone with [NSTimeZone setDefaultTimeZone:otherTimeZone]
Create EKEventEditViewController to add new event with startDate = [NSDate date]
New event start is displayed correctly (current time adjusted to time zone)
Situation 2 - unexpected behavior:
Launch app
Change default timezone with [NSTimeZone setDefaultTimeZone:otherTimeZone]
Create EKEventEditViewController to add new event with startDate = [NSDate date]
New event start is displayed incorrectly (system timezone offset + default timezone offset)
Change default timezone back to system timezone [NSTimeZone setDefaultTimeZone:[NSTimeZone systemTimeZone]]
Create EKEventEditViewController to add new event with startDate = [NSDate date]
New event start is still displayed incorrectly (system timezone offset + default timezone offset)
My guess that on first display of EKEventEditViewController it somehow caches default timezone and then uses it as an offset.
Has anyone faced similar problem? Is this a bug or am I missing something?
I had exact same problem. I was storing all the dates in the database in GMT timeZone with offsets (separately). My app uses custom timeZone from the beginning it's being run (GMT). When I wanted to use those dates while exporting an events to the calendar, I was seeing wrong start and end dates. What helped me solving the problem was firstly convert the dates I had stored in the database to the system Time Zone using the following converter method (see below). Such converted date passed to the EKEventEditViewController was then showing the dates correctly. Hope it will solve your problem too.
+ (NSDate *) convertToSystemTimeZone:(NSDate*)sourceDate {
NSTimeZone* sourceTimeZone = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];
NSInteger sourceGMTOffset = [sourceTimeZone secondsFromGMTForDate:sourceDate];
NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:sourceDate];
NSTimeInterval interval = destinationGMTOffset - sourceGMTOffset;
NSDate* destinationDate = [[[NSDate alloc] initWithTimeInterval:interval sinceDate:sourceDate] autorelease];
return destinationDate; }
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.
This question already has answers here:
Getting date from [NSDate date] off by a few hours
(3 answers)
Closed 9 years ago.
When i create an object for NSDate and put cursor on that object it was showing currect date like below
and when am trying to log that object it was showing date with minus 5:30hr like below
and when I add offset to date and put cursor on that object it was showing date with plus 5:30hr like below
NSInteger offset = [[NSTimeZone defaultTimeZone] secondsFromGMT];
and when am trying to log that object it was showing exact date like below
Why its happening like this? Is this problem with timezone?
Thanks in advance.
NSDate always comes as a GMT. So you have to format the date as per your required timeZone.. You can set your device timeZOne or can use Calendar to set the timeZOne..
NSDate is a "raw" date. That's why it is in GMT and your local and default time zone is GMT +5. It's up to the code to use NSDateFormatter to output the date to a value that makes sense for the user. Try this.
NSDate* sourceDate = [NSDate date];
NSTimeZone* sourceTimeZone = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];
NSInteger sourceGMTOffset = [sourceTimeZone secondsFromGMTForDate:sourceDate];
NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:sourceDate];
NSTimeInterval interval = destinationGMTOffset - sourceGMTOffset;
NSDate* destinationDate = [[[NSDate alloc] initWithTimeInterval:interval sinceDate:sourceDate]];
NSDate description return string representation in the international
format YYYY-MM-DD HH:MM:SS ±HHMM, where ±HHMM represents the time zone
offset in hours and minutes from GMT.
If you want currentLocale, Use:
[date descriptionWithLocale:[NSLocale currentLocale]]
I am trying to get current date with adding device time zone but is show 1 hr late that original date. I thing , I am getting problem of DaylightSavingTime.
How to disable isDaylightSavingTime = FALSE .
here is the code, I have used..
NSDate *date = [NSDate Date];
NSTimeZone *currentTimeZon = [NSTimeZone localTimeZone];
if ([currentTimeZon isDaylightSavingTime])
{
NSLog(#"East coast is NOT on DT");
}
else
{
NSLog(#"East coast is on DT");
}
NSTimeInterval timeZoneOffset = [currentTimeZon secondsFromGMTForDate:currentDate];
NSTimeInterval gmtTimeInterval = [date timeIntervalSinceReferenceDate] - timeZoneOffset;
NSDate *gmtDate = [NSDate dateWithTimeIntervalSinceReferenceDate:gmtTimeInterval];
NSLog(#"### Announcement gmtDate = %#",gmtDate);
I am getting time with 1 Hour difference, date is perfact.
Use NSCalendar, it understands time zones, daylight savings, etc. As #albertamg says, NSDate is just the time since a reference at UTC (GMT), it has no other concept.
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.
All,
This seems like such a simple thing, but I cannot find* the right method to create a UIDatePicker, in time mode, and have it initialized to a specific time. I don't want date -- just time (think alarm clock). I have created a NSDate object:
NSDate * date = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate: (NSTimeInterval) delta];
pickerView = [[UIDatePicker alloc] init]; // which should be 'now' right?
pickerView.datePickerMode = UIDatePickerModeTime; // which creates just the clock
[pickerView setDate:date];
and in the first line, the interval (delta) is zero. It displays 7:00PM.
This has gotta be so simple that I'm missing it, but I can't find the right way -- anyone?
Thank you in advance!
:bp:
*yes, I have looked, but apparently not in the correct places :(
Take the time zone into account. You will get 0AM only if you are at UTC.
Thank you dkk -- I appreciate your help. The real answer was to not use a DatePicker, but to use a PickerView (w/o the date). That made things simpler and do-able.
Thanks again.
NSDate *date = [NSDate date];
date = [[NSCalendar autoupdatingCurrentCalendar] dateFromComponents:[[NSCalendar autoupdatingCurrentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:date]];
date = [date dateByAddingTimeInterval:60 * 60 * 21];
pickerView.date = date;
The steps here with the date are
initialise date with the current date
get the date at midnight
add a time interval to the date (60 seconds * 60 minutes * hour). In this case 21 = 9pm
This works for UIDatePicker with datePickerMode of UIDatePickerModeTime & UIDatePickerModeCountDownTimer