Producing an NSDate with fixed time - objective-c

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.

Related

NSDateComponents keep changing the GMT?

This might be basic but i couldn't find a similar problem to clearly understand that.
I have some date which is this :
2015-07-19 12:00:00 +0000
then i am taking this date and try to get the hour of it with :
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *components = [gregorianCalendar components:NSCalendarUnitDay | NSCalendarUnitHour |NSCalendarUnitMinute | NSCalendarUnitMonth | NSCalendarUnitYear| NSCalendarUnitWeekday fromDate:tdate];
long hour=[components hour];
NSLog(#"-- %ld ",hour); //gives 15
Then i get the hour as 15 and not 12 as the original date .
The 3 hours different is i guess my GMT +3 .
How can i get 12 - the original date hour ?
adding this
[components setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
didn't helped.
When i create that original date with components class, i do it in the exact way that i later do it again, so there shouldn't be any change in the GMT times.
To create the original date i do :
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay |NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitWeekday | NSCalendarUnitHour | NSCalendarUnitMinute fromDate:new];
[components setHour:12];
So, why when you extract it in the exact same way you dont get the same result ?
thanks .
When Using NSCalender and NSDateCompoment it will always translate date to your systemDate. If you want to have that Date invariant and meanwhile use DateCompoment to access components you need to remove the timeInterval between your systemeData to that date system(GMT in your case).
NSTimeZone* currentTimeZone = [NSTimeZone localTimeZone];
NSTimeInterval timeDiff = [currentTimeZone secondsFromGMTForDate:aGMTDate];
NSDate *gmtDate = [[NSDate alloc] initWithTimeInterval:(-timeDiff) sinceDate:[NSDate date]];

Get NSDate from week and day

I am trying to get an NSDate from a day and week post to today.
E.g. week = 2 and day = 4, which would be thursday in two weeks from now (given the week starts on Monday).
I tried a bunch of different things using NSCalendar and NSDateComponents, but nothing came close.
Searched a bit as well, but haven't found any other topic regarding my problem.
The last thing I tried was the following:
- (NSDate *)getDateForIndexPath:(NSIndexPath *)indexPath
{
int week = ((indexPath.row / 7) % 5);
int day = (indexPath.row % 7);
NSDate *referenceDate = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"es_ES"]];
[calendar setTimeZone:[NSTimeZone localTimeZone]];
NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit|NSMonthCalendarUnit | NSWeekCalendarUnit |NSWeekdayCalendarUnit) fromDate:referenceDate];
[dateComponents setWeekday:day];
[dateComponents setWeek:dateComponents.week+(week-1)];
[dateComponents setWeek:dateComponents.week];
NSDate *followingDate = [calendar dateFromComponents:dateComponents];
NSLog(#"Week: %d - Day: %d", week, day);
NSLog(#"followingDate: %#", followingDate);
return followingDate;
}
This gave me the same date over and over again, besides the fact that it sees day 0 as sunday:
2014-04-08 00:02:33.706 TVSports[79878:60b] Week: 1 - Day: 0
2014-04-08 00:02:33.707 TVSports[79878:60b] followingDate: 2014-04-11 22:00:00 +0000
2014-04-08 00:02:33.708 TVSports[79878:60b] Week: 1 - Day: 1
2014-04-08 00:02:33.708 TVSports[79878:60b] followingDate: 2014-04-05 22:00:00 +0000
2014-04-08 00:02:33.709 TVSports[79878:60b] Week: 1 - Day: 2
2014-04-08 00:02:33.709 TVSports[79878:60b] followingDate: 2014-04-06 22:00:00 +0000
2014-04-08 00:02:33.710 TVSports[79878:60b] Week: 1 - Day: 3
2014-04-08 00:02:33.710 TVSports[79878:60b] followingDate: 2014-04-07 22:00:00 +0000
This:
NSDate *referenceDate = [NSDate date];
...
NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit|NSMonthCalendarUnit | NSWeekCalendarUnit |NSWeekdayCalendarUnit) fromDate:referenceDate];
Returns a date components populated correctly for today because you've asked for today's date, then asked the calendar to break that down as year, month, week and weekday.
Following that, this:
[dateComponents setWeekday:day];
[dateComponents setWeek:dateComponents.week+(week-1)];
[dateComponents setWeek:dateComponents.week];
Sets the day. Then it reads the current set week and adds week-1 to it (so week 1 will be this week, week 2 will be next week, etc). It then redundantly reads the week again and sets it again.
Your output shows that the code works correctly. Apple is an American company so weekday 0 is always Sunday to them. But they're aware that Sunday isn't the first day of the week in most places so your code asks for "Sunday (day 0), this week" — not "Sunday this week if we pretend that the week started on Sunday". It says Sunday is the 11th. Allowing for timezone differences, that's correct.
Notice that NSDates do not have a time zone. An NSDate is an opaque record of a particular moment in time. How you would communicate that moment is immaterial. They log in GMT for the sake of being able to say something.
You then ask for Monday, Tuesday and Wednesday and it returns the 5th, 6th and 7th. All correct.
Side note: just use:
NSCalendar *calendar = [NSCalendar currentCalendar];
To use the current system calendar.
You can do this to get the Thursday in two weeks:
typedef NS_ENUM(NSUInteger, WeekDay){
WeekDaySunday = 1,
WeekDayModay,
WeekDayTuesday,
WeekDayWensday,
WeekDayThursday,
WeekDayFriday,
WeekDaySaturday
};
NSDate *now = [NSDate date];
NSDate *beginOfThisWeek;
NSCalendar *cal = [NSCalendar currentCalendar];
[cal setFirstWeekday:WeekDayModay];
[cal rangeOfUnit:NSWeekCalendarUnit // get the beginning of this week
startDate:&beginOfThisWeek // save the beginning to this variable
interval:NULL // we do not care for the weeks length
forDate:now];
NSDateComponents *twoWeeks = [[NSDateComponents alloc] init];
twoWeeks.week = 2;
twoWeeks.day = WeekDayThursday - WeekDaySunday -1 ; // we need the difference between thursday and the beginning of the week
NSDate *thurdayInTwoWeeks = [cal dateByAddingComponents:twoWeeks
toDate:beginOfThisWeek
options:0];

NSDate calculations summertime

I have a timestamp (NSDate) and I want to validate if another timestamp happened in the same calendar week, month, year, day, etc.
I tried to do this by defining 2 other NSDates, one as start date and one as end date.
And then representing the desired timespan with these two dates.
Example for defining the start of the current day:
NSDate *myDate = [[NSDate alloc] init];
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:(
NSEraCalendarUnit |
NSMonthCalendarUnit |
NSYearCalendarUnit |
NSDayCalendarUnit |
NSHourCalendarUnit |
NSMinuteCalendarUnit |
NSSecondCalendarUnit |
NSTimeZoneCalendarUnit
) fromDate:myDate];
[components setHour:1];
[components setMinute:0];
[components setSecond:0];
startDate = [cal dateFromComponents:components];
This should set startDate to the time 00:00:00 on the current date.
The problem is that this only works if myDate has current timezone. E.g. if we have winter time now, and NSDate is summer time it sets the time 1 hour wrong.
How can I consider the summer/winter time in this calculation, or is there a better way to represent a concrete timespan a calendar based timespan a timestamp lies in?
The easiest way to get a day/week/month/... timespan for a given date is the
rangeOfUnit method. For example:
NSDate *date1, *date2;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *startOfTimespan;
NSTimeInterval lengthOfTimespan;
[calendar rangeOfUnit:NSWeekOfYearCalendarUnit
startDate:&startOfTimespan
interval:&lengthOfTimespan
forDate:date1];
Now startOfTimespan is the start of the week that contains date1,
and lengthOfTimespan is the length of that week. So you can test date2 with
NSTimeInterval diff = [date2 timeIntervalSinceDate:startOfTimespan];
if ( diff >= 0 && diff < lengthOfTimespan) {
// date1 and date2 are in the same week
}

How to skip time in NSDate?

I want to get difference between dates skipping time means if one date is 13 Jan 2012 - 11 pm and other date is 14 Jan 2012 - 12 am,then difference should be 1 day not 0 day.I mean I want difference between date only, 14 Jan 2012 - 13 Jan 2012, skipping time. I know I can use NSDate api to calculate difference but the problem is it consider time also.So I thought while calculating difference I will skip time but I do not know how to skip time because if I use NSDateFormatter it will return string not date.Please help me what I can do?
Thanks in advance!
What you need to do is get the NSDateComponents of each date first. Once you do that you can compare the 'day' component to get you difference.
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[cal setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSDate *date1 = ....;
NSDate *date2 = ....;
NSDateComponents *comps1 = [cal components:NSDayCalendarUnit|NSYearCalendarUnit|NSMonthCalendarUnit fromDate:date1];
NSDateComponents *comps2 = [cal components:NSDayCalendarUnit|NSYearCalendarUnit|NSMonthCalendarUnit fromDate:date2];
date1 = [cal dateFromComponents:comps1];
date2 = [cal dateFromComponents:comps2];
NSDateComponents *diffComps = [cal components:NSDayCalendarUnit fromDate:date1 toDate:date2 options:0];
NSLog(#"Days diff = %d", diffComps.day);
The date API can be kind of weird to wrap your head around, but once you do it is quite powerful.

Difference between NSDate and NSDateComponent value for the same date

I created a simple function to get first and last day of a week for a day in it.
Looking at the NSLog output i found that different values are returned from a NSDate descriptor and component day for the same date, why ?
Here NSLog outputs:
NSDATE: 2011-04-03 22:00:00 +0000, DAY COMPONENT: 4
NSDATE: 2011-04-09 22:00:00 +0000, DAY COMPONENT: 10
As you can see, NSDATE is 3 of April and day component is 4 for the first row, and respectively 9 and 10 for the second one.
Here the code:
NSDate *date = [NSDate date]; //Today is April 5th 2011
NSCalendar *cal =[[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
[cal setFirstWeekday:2]; //My week starts from Monday
//DEFINE BEGINNING OF THE WEEK
NSDate *beginningOfWeek = nil;
[cal rangeOfUnit:NSWeekCalendarUnit startDate:&beginningOfWeek interval:nil forDate:date];
NSDateComponents *beginComponents = [cal components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit) fromDate:beginningOfWeek];
//DEFINE END OF THE WEEK, WITH 6 days OFFSET FROM BEGINNING
NSDateComponents *offset = [[NSDateComponents alloc]init];
[offset setDay:6];
NSDate *endOfWeek = [cal dateByAddingComponents:offset toDate:beginningOfWeek options:0];
NSDateComponents *endComponents = [cal components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit) fromDate:endOfWeek];
NSLog(#"NSDATE: %#, DAY COMPONENT: %d",beginningOfWeek, [beginComponents day]);
NSLog(#"NSDATE: %#, DAY COMPONENT: %d",endOfWeek, [endComponents day]);
Your dates are being printed with a timezone of +0000 (UTC), while your NSCalendar instance (and therefore your NSDateComponents) is using your device's default timezone (which I would guess is UTC+2).