Using NSDateComponents to test date equality when times differ - objective-c

I want to test if two NSDate objects have the same year/month/day but different times of day. Here is my code:
NSDate *date1 = [dataDictionary1 valueForKey:#"date"];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
calendar.timeZone = [NSTimeZone systemTimeZone];
NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:date1];
NSDate *newDate1 = [calendar dateFromComponents:components];
NSDate *date2 = [dataDictionary2 valueForKey:#"date"];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
calendar.timeZone = [NSTimeZone systemTimeZone];
NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:date2];
NSDate *newDate2 = [calendar dateFromComponents:components];
However, newDate1 is returning with 2012-05-01 05:00:00 +0000 and newDate2 with 2012-05-01 04:00:00 +0000.
The hours are not zero because my time zone is not GMT, but why are the two hours not equal? Do you know a better way to test if dates with differing times are equal? (That is, more efficient than getting date components for each and testing equality for each day/month/year?)

Try this:
NSDate *date1 = [dataDictionary1 valueForKey:#"date"];
long noTime1 = [date1 timeIntervalSinceReferenceDate] / (60*60*24);
NSDate *date2 = [dataDictionary2 valueForKey:#"date"];
long noTime2 = [date2 timeIntervalSinceReferenceDate] / (60*60*24);
if (noTime1 == noTime2) {
// same date
}
Of course this only works if you simply want to compare the date portion and don't care about the actual day, month, or year values.

Related

I have a method that takes timezone name as a parameter and gives the current date's day component. But it gives different incorrect results

Suppose i have two parameters
Australia/Sydney (GMT+10) offset 36000 &
Asia/Kolkata (IST) offset 19800
as timezones, it gives different values for the day component of current day itself. I am not able to figure out what am i doing wrong.. :( A little clue will be appreciated
-(NSInteger)getDayWithTimeZoneName:(NSString *)timeZoneName{
// Instantiate a timezone
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:timeZoneName];
//Instantiate a date formatter
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setLocale:[NSLocale currentLocale]];
[df setTimeZone:timeZone];
[df setDateFormat:#"yyyy-MM-dd"];
NSString *dateStr = [df stringFromDate:[NSDate date]];
NSDate *date = [df dateFromString:dateStr];
// NSDateComponents *components = [[NSCalendar currentCalendar] components: NSCalendarUnitDay fromDate:date];
NSDateComponents *components = [[[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar]components:NSDayCalendarUnit fromDate:date];
NSInteger day = [components day];
NSLog(#"Date component for timeZone %# is %ld", timeZoneName,(long)day);
return day;
}
NSFormatter isn't designed to convert or calculate dates:
NSString *dateStr = [df stringFromDate:[NSDate date]];
dateStr is the date in Sydney (2016-05-16 0:00).
NSDate *date = [df dateFromString:dateStr];
date is GMT, 10 hours behind Sydney (2016-05-15 14:00).
Use NSCalendar to calculate dates:
NSCalendar *calendar = [NSCalendar currentCalendar];
calendar.timeZone = timeZone;
NSDateComponents *components = [calendar components:NSCalendarUnitDay fromDate:[NSDate date]];
NSInteger day = [components day];

Get the future time as NSDate

I have a date picker. After choosing a time from this I would like to get the dates and time of next 30 min and 1 hour.
How would I go about writing a method to take a date and time and return as two NSDates for the next 30 min and 1 hour from that date-time.
Example: I picked time 1:30 pm from date picker then I want to fetch next 30 min time and 1 hour time with there time set.
Can any one help on this ??
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [NSDateComponents new];
components.minute = 30;
components.hour = 1;
NSDate *date = [calendar dateByAddingComponents:components toDate:< your date > options:0];
You can just use dateByAddingTimeInterval method of NSDate.
Example :
NSDate *NextDateOneHour = [oldDate dateByAddingTimeInterval:3600]; //3600 second equivalent to 60 mins
NSDate *NextDateHalfAnHour = [oldDate dateByAddingTimeInterval:1800]; //1800 second equivalent to 30 mins
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setHour:1];
NSDate *afterHour = [gregorian dateByAddingComponents:comps toDate:[NSDate date] options:0];
[comps setMinute:30];
NSDate *afterHalfHour = [gregorian dateByAddingComponents:comps toDate:[NSDate date] options:0];

Calculate NSDate for day after summertime

I just found a but in one of my apps; the problem is that I am calculating the days in a menu using initWithTimeIntervalSinceNow and adding the caculation (day*X) (X meaning the day in question).
However, the night between 27th and 28th of oct the CEST timezone will become CET thus meaning that for one day the time should be calculated by (day*X)+3600. However, I do not want to use if cases and believe there should be a better way of dealing with this.
How can I calculate future days with keeping summer/winter time in mind?
My code:
int day = (60*60*24);
NSDate *today = [NSDate date];
NSDate *days1 = [[NSDate alloc] initWithTimeIntervalSinceNow:day];
NSDate *days2 = [[NSDate alloc] initWithTimeIntervalSinceNow:(day*2)];
NSDate *days3 = [[NSDate alloc] initWithTimeIntervalSinceNow:(day*3)];
NSDate *days4 = [[NSDate alloc] initWithTimeIntervalSinceNow:(day*4)];
NSDate *days5 = [[NSDate alloc] initWithTimeIntervalSinceNow:(day*5)];
NSDate *days6 = [[NSDate alloc] initWithTimeIntervalSinceNow:(day*6)];
NSDate *days7 = [[NSDate alloc] initWithTimeIntervalSinceNow:(day*7)];
Try this:
- (NSDate *)dateByAddingXDaysFromToday:(int)days
{
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.day = days;
return [[NSCalendar currentCalendar] dateByAddingComponents:comps toDate:[NSDate date] options:0];
}
Then you can use:
NSDate *days1 = [self dateByAddingXDaysFromToday:1];
//etc...
It's not clear what you are trying to achieve with calculating the date objects. I'm assuming you want to create objects that refer the next seven days, same time as now.
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:1];
NSDate *now = [NSDate date];
NSDate *days1 = [calendar dateByAddingComponents:components toDate:now options:0];
NSDate *days2 = [calendar dateByAddingComponents:components toDate:days1 options:0];
NSDate *days3 = [calendar dateByAddingComponents:components toDate:days2 options:0];
....

Determine number of hours in a given day (plus or minus DST shift hours)

Given an NSDate and an NSCalendar, how do I determine the number of hours in the day that follows the given date. This would be 23, 24, or 25, depending on whether the following day is entering daylight savings (23), normal (24) or exiting daylight savings (25).
You can ask the calendar how long any unit is (and when that unit starts) with rangeOfUnit:startDate:interval:forDate:.
// Test date (the day DST begins)
NSDateComponents *components = [[NSDateComponents alloc] init];
components.year = 2012;
components.month = 3;
components.day = 11;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *date = [calendar dateFromComponents:components];
NSTimeInterval dayLength;
[calendar rangeOfUnit:NSDayCalendarUnit startDate:NULL interval:&dayLength forDate:date];
NSLog(#"%f seconds", dayLength);
Note that rangeOfUnit:... can techincally fail and return NO, but if you control the inputs that shouldn't be able to happen.
// Test input
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"yyyy MM dd HH:mm:ss";
NSDate *referenceDate = [formatter dateFromString:#"2012 03 24 13:14:14"];
// Get reference date with day precision
NSCalendar *calendar = [NSCalendar currentCalendar];
unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *components = [calendar components:unitFlags fromDate:referenceDate];
NSDate *today = [calendar dateFromComponents:components];
// Set components to add 1 day
components = [[NSDateComponents alloc] init];
components.day = 1;
// The day after the reference date
NSDate *tomorrow = [calendar dateByAddingComponents:components toDate:today options:0];
// The day after that
NSDate *afterTomorrow = [calendar dateByAddingComponents:components toDate:tomorrow options:0];
// Difference in hours: 23, 24 or 25
NSUInteger hours = [afterTomorrow timeIntervalSinceDate:tomorrow] / 3600;

How to get relative dates

how can I get relative dates in Objective-C?
If I have "today", how do I find "yesterday", "last week", "last two weeks", "one month ago", "two months ago"?
So if you have an NSDate *today = [NSDate date];, then you can use NSDateComponents to get relative dates.
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *today = [NSDate date];
NSDateComponents *yesterdayComponents = [[NSDateComponents alloc] init];
[yesterdayComponents setDay:-1];
NSDate *yesterday = [calendar dateByAddingComponents:yesterdayComponents toDate:today options:0];
[yesterdayComponents release];
NSDateComponents *twoWeeksAgoComponents = [[NSDateComponents alloc] init];
[twoWeeksAgoComponents setWeek:-2];
NSDate *twoWeeksAgo = [calendar dateByAddingComponents:twoWeeksAgoComponents toDate:today options:0];
[twoWeeksAgoComponents release];
Etc.
NSDateComponents and NSCalendar handle underflowing and overflowing automatically (unless you turn it off with the options: bit). So if today is "28 February" and you want "tomorrow", it will automatically choose either "29 February" or "1 March" depending on the year. It's pretty cool. This is also the only proper way of doing date manipulation.