NSDate calculations summertime - objective-c

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
}

Related

NSDateComponents not printing accurate day/month/year times [duplicate]

This question already has answers here:
Age extracted from birth date always off by inconsistent amount
(2 answers)
Closed 5 years ago.
I'm using NSDateComponents to get each day, month, year, hour, minute, etc separately but day, month, year and seconds are not accurate with 2017-11-08 1:00:00....Does anybody know what I'm missing?
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd hh:mm:ss"];
NSDate *date = [dateFormatter dateFromString:#"2017-11-08 1:00:00"];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:date];
NSInteger day = [components day];
NSInteger month = [components month];
NSInteger year = [components year];
NSInteger hour = [components hour];
NSInteger minute = [components minute];
NSInteger second = [components second];
NSLog(#"day: %ld",(long)day);
NSLog(#"month: %ld",(long)month);
NSLog(#"year: %ld",(long)year);
NSLog(#"hour: %ld",(long)hour);
NSLog(#"minute: %ld",(long)minute);
NSLog(#"second: %ld",(long)second);
Output:
day: 2147483647
month: 2147483647
year: 2147483647
hour: 1
minute: 0
second: 2147483647
You're only getting the hour and minute, because that's all you're asking for. If you actually ask for the day, month, year, and second, you'll get them:
NSCalendarUnit units = NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear |
NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
NSDateComponents *components = [calendar components:units fromDate:date];

NSDate intervals for yesterday

I need to filter search results based on values that were added yesterday. I have seen plenty on finding yesterday using:
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:( NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:[[NSDate alloc] init]];
[components setHour:-24];
[components setMinute:0];
[components setSecond:0];
NSDate *yesterday = [cal dateByAddingComponents:components toDate:[NSDate date] options:0];
predicate = [NSPredicate predicateWithFormat:#"created_at >= %#", yesterday];
But this finds 24 hours since this exact moment in time. I need to filter yesterday as 12:01am-12:00pm. So the actual 24 hour period that was yesterday.
I'm guessing that I need to do something along the lines of:
1. Take the current date
2. Find the time from the current date to 12:01am of the same day
3. Then subtract 24 hours from that date
I feel confident I can do #3 (and #1 of course), but I'm not sure how to go about #2. I maybe over thinking it but I can't seem to grasp how to say: "Ok, it's 8:03am, I need to remove 8 hours and 2 minutes which will put me at 12:01am".
Start with some date of today, for example "now":
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
Subtract one day to get some date of yesterday:
NSDateComponents *minusOneDay = [[NSDateComponents alloc] init];
[oneDay setDay:-1];
NSDate *nowMinusOneDay = [cal dateByAddingComponents:minusOneDay toDate:now options:0];
Compute start and end date of the "day calendar unit" that contains yesterday's date:
NSDate *startOfYesterday;
NSTimeInterval lengthOfYesterday;
[cal rangeOfUnit:NSDayCalendarUnit startDate:&startOfYesterday interval:&lengthOfYesterday forDate:nowMinusOneDay];
NSDate *endOfYesterday = [startOfYesterday dateByAddingTimeInterval:lengthOfYesterday];
This should work even if a daylight savings time transition occurs between today and yesterday.
Generally one should avoid to use explicit time intervals such as "24 hours", because not every day has that length.

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.

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.

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).