NSDate results from -(NSDate *)dateFromComponents:(NSDateComponents *)comps - objective-c

I want to get a NSDate object with NSDateComponents but the hour of the NSDate is 1 hour lower then in the components.
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[cal setLocale:[NSLocale currentLocale]];
[cal setTimeZone:[NSTimeZone localTimeZone]];
NSDateComponents *hourComp = [[NSDateComponents alloc] init];
hourComp.timeZone = [NSTimeZone localTimeZone];
[hourComp setHour:18];
NSLog(#"%#",hourComp);
NSLog(#"%#",[cal dateFromComponents:hourComp]);
NSLog(#"%#",[NSDate date]);
Console Output:
2012-04-10 19:10:57.505 TestDate[9861:f803] <NSDateComponents: 0x6b6ad30>
TimeZone: Europe/Berlin (CEST) offset 7200 (Daylight)
Hour: 18
2012-04-10 19:10:57.507 TestDate[9861:f803] 0001-01-01 17:06:32 +0000
2012-04-10 19:10:57.508 TestDate[9861:f803] 2012-04-10 17:10:57 +0000
What I want is 18:xx:xx

I note that you're in Europe, and one hour ahead of GMT. When you set the date to 18:xx it thinks you are setting it in Europe, and so it subtracts one hour before storing it in GMT. When you print it out, you're not asking it to be formatted for local time, so it's giving you GMT, which is 17:xx.
You need to use an NSDateFormatter, and set its locale and time zone - just as you did with the NSCalendar object - and then call stringFromDate on it, passing the date you've created.

Related

Getting wrong date while add event in iPhone Reminder app from my application

I am adding an event with NSDate value
“2017-04-25 15:00:00 +0000”
As per my timezone, it’s 2017-04-25 08:40 PM.
I am getting NSDate value from a function.
NSString *strDateTime = #"Tuesday, 25 Apr 2017 08:30 PM";
NSDateFormatter *formatterLocal = [[NSDateFormatter alloc] init];
[formatterLocal setTimeZone:[NSTimeZone systemTimeZone]];
[formatterLocal setDateFormat:#"EEEE, dd MMM yyyy hh:mm a"];
NSDate *dateAdd = [formatterLocal dateFromString:strDateTime];
While I check reminder app it’s showing event with date 25/04/17, 3:00 PM. While it should be 25/04/17, 8:00 PM.
Can anyone please help me out from this!
I have already checked Get wrong time when adding an event to default calendar in iPhone
I just catch my mistake.
I have set the wrong timezone in "dueDateComponents".
Below is my code.
EKReminder *reminder = [EKReminder reminderWithEventStore:self.eventStore];
reminder.dueDateComponents = [self dateComponentsForDefaultDueDate];
- (NSDateComponents *)dateComponentsForDefaultDueDate {
/*
Changing date components
*/
NSCalendar *cal = [NSCalendar currentCalendar];
//[cal setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
NSDateComponents *components = [cal components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear |NSCalendarUnitHour | NSCalendarUnitMinute fromDate:[NSDate dateWithTimeIntervalSince1970:[_dictData[#"start"] longLongValue]]];
components.hour = [components hour];
components.minute = [components minute];
return components;
}
I just commented
//[cal setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
Silly mistake :p

NSDate is wrong when doing 'dateFromString'

Im here in the UK and when working with dates in iOS they are always out by one hour (one hour behind), what I need is the correct time from an NSDate. Ive done the following, but i get two different times:
NSDate *today = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
dateFormatter.dateFormat = #"yyyy-MM-dd HH:mm:ss";
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
NSLog(#"NSDate %#",today);
NSLog(#"Time %#", [dateFormatter stringFromDate:today]);
NSDate*stringDate = [dateFormatter dateFromString:[dateFormatter stringFromDate:today]];
NSLog(#"Time date %#",stringDate);
Here is what is logged:
NSDate 2015-07-01 16:07:22 +0000
Time 2015-07-01 17:07:22
Time date 2015-07-01 16:07:22 +0000
Why is this happening? Am i missing something obvious? Surely if the string date is correct, then doing dateFromString should yield the correct results?
The reason I need an NSDate is so I can get the correct amount of seconds using [myTime timeIntervalSince1970]
2015-07-01 17:07:22 //is the correct date
Im expecting an NSDate object that is correct to my date and time.
Update
The answers below helped me find where I was going wrong, so I changed my approach, I was able to get the current timestamp doing the following:
NSString *timeStamp = [dateFormatter stringFromDate:[NSDate date]];
NSDate *curdate = [dateFormatter dateFromString:timeStamp];
int unix_timestamp = [curdate timeIntervalSince1970];
NSDate* referenceDate = [NSDate dateWithTimeIntervalSince1970: 0];
NSTimeZone* timeZone = [NSTimeZone systemTimeZone];
int offset = (int)[timeZone secondsFromGMTForDate: referenceDate];
int currentTimestamp = unix_timestamp + offset;
NSLog(#"CUrrent time stamp %d",currentTimestamp);
NSDate is an absolute moment of time, it does not have a timezone. The date object you have is correct: it is exactly the moment that code was executed.
If you need string representation of that moment of time in a specific time zone, use stringFromDate: just like you did.
If you need to know number values of hour/minute in a specific time zone, use -[NSCalendar components:fromDate:].
[calendar setTimeZone:...];
NSDateComponents* components = [calendar components:(NSHourCalendarUnit|NSMinuteCalendarUnit) fromDate:date];
The date formatter defaults to the local timezone. If you want a different timezone specify it. NSLog of a date used the 'NSDatedescription` method that defaults to GMT (UTC).
Examining the code:
NSDate *today = [NSDate date];
// Creates today's data in GMT (UTC) All NSDates are referenced to GMT.
NSLog(#"NSDate %#",today); (moved up for explanation ordering)
// NSDate 2015-07-01 16:07:22 +0000
// Displays the date in GMT
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
dateFormatter.dateFormat = #"yyyy-MM-dd HH:mm:ss";
[dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
// Creates a date for matter with the system timezone
NSLog(#"Time %#", [dateFormatter stringFromDate:today]);
// Time 2015-07-01 17:07:22
// Creates a string representation in the system timezone and displays it
NSDate*stringDate = [dateFormatter dateFromString:[dateFormatter stringFromDate:today]];
// Creates a date from the string taking into the system timezone
NSLog(#"Time date %#",stringDate);
// Time date 2015-07-01 16:07:22 +0000
// Displays the date in GMT.

setFirstWeekday doesn't work

I have an issue: setFirstWeekDay doesn't work... I don't know why ...
NSCalendar *gregorianT = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorianT setFirstWeekday:2];
NSDateFormatter *formatDayWeek = [[NSDateFormatter alloc] init];
[formatDayWeek setDateFormat:#"c EEEE"];
NSLog(#"date : %# value for date : %#", dateForMonth, [formatDayWeek stringFromDate:dateForMonth]);
This is what I got:
date : 2012-11-23 14:18:28 +0000 value for date : 6 Friday
And I should get date : 2012-11-23 14:18:28 +0000 value for date : 5 Friday
The issue is that you are really dealing with three separate objects here: an NSCalendar, an NSDate, and an NSDateFormatter (which is not using the NSCalendar object you created). The three aren't implicitly connected; when you pass in the NSDate to the date formatter, you're completely pulling your custom NSCalendar, with the modified weekday, out of the equation. Remember: an NSDate object is simply a measure of time from a reference point (such as number of seconds from 1/1/2001 Midnight GMT)... it's the calendar object that has the concept of "day name," day ordinality," etc for that measure of time.
If you want to see the modified ordinality, pass in your calendar object to the formatter:
NSCalendar *gregorianT = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorianT setFirstWeekday:2];
NSDateFormatter *formatDayWeek = [[NSDateFormatter alloc] init];
[formatDayWeek setCalendar:gregorianT];
[formatDayWeek setDateFormat:#"c EEEE"];
NSLog(#"Value for date: %#", [formatDayWeek stringFromDate:dateForMonth]);
...or you can access the ordinality directly from your NSCalendar object.
NSCalendar *gregorianT = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorianT setFirstWeekday:2];
NSUInteger valueOfDay = [gregorianT ordinalityOfUnit:NSWeekdayCalendarUnit inUnit:NSWeekCalendarUnit forDate:dateForMonth];
NSLog(#"Value for date : %ld", (long)valueOfDay);

Producing an NSDate with fixed time

I am trying to produce an NSDate with fixed hour and minutes. I need this to make an equal comparison with other date stored in CoreData.
So far I wrote this code:
NSDate date = [NSDate date];
unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* components = [calendar components:flags fromDate:date];
NSDate* newDate = [calendar dateFromComponents:components];
however with a breakpoint in xcode4 I can see the values:
Printing description of date:
2012-01-10 11:20:47 +0000
Printing description of newDate:
2012-01-09 23:00:00 +0000
Why newDate is one day back in respect of date ?
/* EDIT */
I also have tried to set manually all the components, but calendar dateFromComponents always give back same one hour back date, seems ignoring the components.
components.hour=0;
components.minute=0;
components.second=0;
components.timeZone=[NSTimeZone localTimeZone];
This is the description of component after being set:
<NSDateComponents: 0x7464de0>
TimeZone: Europe/Rome (CET) offset 3600
Calendar Year: 2012
Month: 1
Day: 10
Hour: 0
Minute: 0
Second: 0
which is exactly what I would like to have, but the calculated date with this component is still
Printing description of newDate:
2012-01-09 23:00:00 +0000
I wonder why I cannot get a precise NSDate even with specifying all the components in an NSDateComponents. Just because NSCalendar is ignoring my requirements, what's the meaning of components ?
What am I doing wrong ?
I guess you are +01:00 time zone. Actually the NSDate always gives values in GMT. So if it is Jan 10th, 00:00, then at the same time GMT time is Jan 9th, 23:00.
Even, while printing the following line
2012-01-10 11:20:47 +0000,
it should have printed 1 hour less than your current time. Please check.
Use this....
NSDate *date = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setLocale:[NSLocale currentLocale]];
NSDateComponents *nowComponents = [gregorian components:NSYearCalendarUnit | NSWeekCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:date];
NSDate* newDate = [gregorian dateFromComponents:nowComponents];
NSLog(#"%#\n%#",date,newDate);
You may have problems with time zones, try setting a time zone for the calendar.

Get an array of future NSDates

I have a date picker.
After choosing a time from this I would like to get the dates of the next 64 Mondays.
How would I go about writing a method to take a date and return an NSArray of NSDates for the next 64 Mondays from that date
for e.g.
I picked time 6:45 pm from date picker then I want to fetch next 64 mondays with there time set to that time.
Example (ARC):
NSDate *pickerDate = [NSDate date];
NSLog(#"pickerDate: %#", pickerDate);
NSDateComponents *dateComponents;
NSCalendar *calendar = [NSCalendar currentCalendar];
dateComponents = [calendar components:NSWeekdayCalendarUnit fromDate:pickerDate];
NSInteger firstMondayOrdinal = 9 - [dateComponents weekday];
dateComponents = [[NSDateComponents alloc] init];
[dateComponents setDay:firstMondayOrdinal];
NSDate *firstMondayDate = [calendar dateByAddingComponents:dateComponents toDate:pickerDate options:0];
dateComponents = [[NSDateComponents alloc] init];
[dateComponents setWeek:1];
for (int i=0; i<64; i++) {
[dateComponents setWeek:i];
NSDate *mondayDate = [calendar dateByAddingComponents:dateComponents toDate:firstMondayDate options:0];
NSLog(#"week#: %i, mondayDate: %#", i, mondayDate);
}
NSLog output:
pickerDate: 2011-12-09 20:38:25 +0000
week#: 0, mondayDate: 2011-12-12 20:38:25 +0000
week#: 1, mondayDate: 2011-12-19 20:38:25 +0000
week#: 2, mondayDate: 2011-12-26 20:38:25 +0000
week#: 3, mondayDate: 2012-01-02 20:38:25 +0000
-the remaining 60 here-
Start with the NSDate from the picker, and keep adding 24*60*60 seconds to it until it's a Monday. Add the resulting date to the result. Continue adding 7*24*60*60 seconds to the last date you added and pushing the result onto the return list until you have all 64 Mondays. Here is how you tell if a NSDate falls on Monday:
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents =[gregorian components:NSWeekdayCalendarUnit fromDate:dateOfInterest];
NSInteger weekday = [weekdayComponents weekday];
if (weekday == 2) ... // 2 represents Monday
EDIT: DaveDeLong pointed out a deficiency in the above algorithm: it will shift the time two times on the days of changing to daylight savings time. Instead of counting seconds manually, use this code to add a day to NSDate:
NSDate *currentDate = [NSDate date];
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:1]; // Add 1 when searching for the next Monday; add 7 when iterating 63 times
NSDate *date = [gregorian dateByAddingComponents:comps toDate:currentDate options:0];
[comps release];
You can use NSCalendar to determine what day of the week today (at the chosen time) is; bump it up to get to the next Monday, and then bump that by by 7 days 63 times to get the Mondays you seem to want.