/* Erica Sadun, http://ericasadun.com iPhone Developer's Cookbook 3.x and beyond BSD License, Use at your own risk */ /* #import : Not planning to implement: dateByAskingBoyOut and dateByGettingBabysitter ---- General Thanks: sstreza, Scott Lawrence, Kevin Ballard, NoOneButMe, Avi`, August Joki. Emanuele Vulcano, jcromartiej, Blagovest Dachev, Matthias Plappert, Slava Bushtruk, Ali Servet Donmez, Ricardo1980, pip8786, Danny Thuerin, Dennis Madsen */ #import "NSDate-Utilities.h" #define DATE_COMPONENTS (NSYearCalendarUnit| NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSWeekdayCalendarUnit | NSWeekdayOrdinalCalendarUnit) #define CURRENT_CALENDAR [NSDate calendarInstance] static NSCalendar *calendar = nil; @implementation NSDate (Utilities) + (NSCalendar *)calendarInstance { if (!calendar) { calendar = [NSCalendar currentCalendar]; } return calendar; } #pragma mark Relative Dates + (NSDate *) dateWithDaysFromNow: (NSInteger) days { NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_DAY * days; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; return newDate; } + (NSDate *) dateWithDaysBeforeNow: (NSInteger) days { NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_DAY * days; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; return newDate; } + (NSDate *) dateTomorrow { return [NSDate dateWithDaysFromNow:1]; } + (NSDate *) dateYesterday { return [NSDate dateWithDaysBeforeNow:1]; } + (NSDate *) dateWithHoursFromNow: (NSInteger) dHours { NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_HOUR * dHours; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; return newDate; } + (NSDate *) dateWithHoursBeforeNow: (NSInteger) dHours { NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_HOUR * dHours; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; return newDate; } + (NSDate *) dateWithMinutesFromNow: (NSInteger) dMinutes { NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_MINUTE * dMinutes; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; return newDate; } + (NSDate *) dateWithMinutesBeforeNow: (NSInteger) dMinutes { NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_MINUTE * dMinutes; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; return newDate; } #pragma mark Comparing Dates - (BOOL) isEqualToDateIgnoringTime: (NSDate *) aDate { NSDateComponents *components1 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; NSDateComponents *components2 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:aDate]; return ((components1.year == components2.year) && (components1.month == components2.month) && (components1.day == components2.day)); } - (BOOL) isToday { return [self isEqualToDateIgnoringTime:[NSDate date]]; } - (BOOL) isTomorrow { return [self isEqualToDateIgnoringTime:[NSDate dateTomorrow]]; } - (BOOL) isYesterday { return [self isEqualToDateIgnoringTime:[NSDate dateYesterday]]; } // This hard codes the assumption that a week is 7 days - (BOOL) isSameWeekAsDate: (NSDate *) aDate { NSDateComponents *components1 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; NSDateComponents *components2 = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:aDate]; // Must be same week. 12/31 and 1/1 will both be week "1" if they are in the same week if (components1.week != components2.week) return NO; // Must have a time interval under 1 week. Thanks @aclark return (fabs([self timeIntervalSinceDate:aDate]) < D_WEEK); } - (BOOL) isThisWeek { return [self isSameWeekAsDate:[NSDate date]]; } - (BOOL) isNextWeek { NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_WEEK; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; return [self isSameWeekAsDate:newDate]; } - (BOOL) isLastWeek { NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] - D_WEEK; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; return [self isSameWeekAsDate:newDate]; } - (BOOL) isSameMonthAsDate: (NSDate *) aDate { NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:self]; NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:aDate]; return ((components1.month == components2.month) && (components1.year == components2.year)); } - (BOOL) isThisMonth { return [self isSameMonthAsDate:[NSDate date]]; } - (BOOL) isSameYearAsDate: (NSDate *) aDate { NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:self]; NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:aDate]; return (components1.year == components2.year); } - (BOOL) isThisYear { return [self isSameYearAsDate:[NSDate date]]; } - (BOOL) isNextYear { NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:self]; NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:[NSDate date]]; return (components1.year == (components2.year + 1)); } - (BOOL) isLastYear { NSDateComponents *components1 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:self]; NSDateComponents *components2 = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:[NSDate date]]; return (components1.year == (components2.year - 1)); } - (BOOL) isEarlierThanDate: (NSDate *) aDate { return ([self compare:aDate] == NSOrderedAscending); } - (BOOL) isLaterThanDate: (NSDate *) aDate { return ([self compare:aDate] == NSOrderedDescending); } #pragma mark Roles - (BOOL) isTypicallyWeekend { NSDateComponents *components = [CURRENT_CALENDAR components:NSYearCalendarUnit fromDate:self]; if ((components.weekday == 1) || (components.weekday == 7)) return YES; return NO; } - (BOOL) isTypicallyWorkday { return ![self isTypicallyWeekend]; } #pragma mark Adjusting Dates - (NSDate *) dateByAddingDays: (NSInteger) dDays { NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_DAY * dDays; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; return newDate; } - (NSDate *) dateBySubtractingDays: (NSInteger) dDays { return [self dateByAddingDays: (dDays * -1)]; } - (NSDate *) dateByAddingHours: (NSInteger) dHours { NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_HOUR * dHours; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; return newDate; } - (NSDate *) dateBySubtractingHours: (NSInteger) dHours { return [self dateByAddingHours: (dHours * -1)]; } - (NSDate *) dateByAddingMinutes: (NSInteger) dMinutes { NSTimeInterval aTimeInterval = [self timeIntervalSinceReferenceDate] + D_MINUTE * dMinutes; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; return newDate; } - (NSDate *) dateBySubtractingMinutes: (NSInteger) dMinutes { return [self dateByAddingMinutes: (dMinutes * -1)]; } - (NSDate *) dateAtStartOfDay { NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; components.hour = 0; components.minute = 0; components.second = 0; return [CURRENT_CALENDAR dateFromComponents:components]; } - (NSDateComponents *) componentsWithOffsetFromDate: (NSDate *) aDate { NSDateComponents *dTime = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:aDate toDate:self options:0]; return dTime; } #pragma mark Retrieving Intervals - (NSInteger) minutesAfterDate: (NSDate *) aDate { NSTimeInterval ti = [self timeIntervalSinceDate:aDate]; return (NSInteger) (ti / D_MINUTE); } - (NSInteger) minutesBeforeDate: (NSDate *) aDate { NSTimeInterval ti = [aDate timeIntervalSinceDate:self]; return (NSInteger) (ti / D_MINUTE); } - (NSInteger) hoursAfterDate: (NSDate *) aDate { NSTimeInterval ti = [self timeIntervalSinceDate:aDate]; return (NSInteger) (ti / D_HOUR); } - (NSInteger) hoursBeforeDate: (NSDate *) aDate { NSTimeInterval ti = [aDate timeIntervalSinceDate:self]; return (NSInteger) (ti / D_HOUR); } - (NSInteger) daysAfterDate: (NSDate *) aDate { NSTimeInterval ti = [self timeIntervalSinceDate:aDate]; return (NSInteger) (ti / D_DAY); } - (NSInteger) daysBeforeDate: (NSDate *) aDate { NSTimeInterval ti = [aDate timeIntervalSinceDate:self]; return (NSInteger) (ti / D_DAY); } #pragma mark Decomposing Dates - (NSInteger) nearestHour { NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_MINUTE * 30; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; NSDateComponents *components = [CURRENT_CALENDAR components:NSHourCalendarUnit fromDate:newDate]; return components.hour; } - (NSInteger) hour { NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; return components.hour; } - (NSInteger) minute { NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; return components.minute; } - (NSInteger) seconds { NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; return components.second; } - (NSInteger) day { NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; return components.day; } - (NSInteger) month { NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; return components.month; } - (NSInteger) week { NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; return components.week; } - (NSInteger) weekday { NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; return components.weekday; } - (NSInteger) nthWeekday // e.g. 2nd Tuesday of the month is 2 { NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; return components.weekdayOrdinal; } - (NSInteger) year { NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self]; return components.year; } @end