// // NSDate+PBCategory.m // IphoneBIMe // // Created by zjf on 2018/8/20. // Copyright © 2018年 ProBIM. All rights reserved. // #import "NSDate+PBCategory.h" static const unsigned componentFlags = (NSCalendarUnitYear| NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekOfMonth | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitWeekday | NSCalendarUnitWeekdayOrdinal); @implementation NSDate (PBCategory) // Courtesy of Lukasz Margielewski // Updated via Holger Haenisch + (NSCalendar *) currentCalendar { static NSCalendar *sharedCalendar = nil; if (!sharedCalendar) sharedCalendar = [NSCalendar autoupdatingCurrentCalendar]; return sharedCalendar; } #pragma mark - Relative Dates + (NSDate *) dateWithDaysFromNow: (NSInteger) days { // Thanks, Jim Morrison return [[NSDate date] dateByAddingDays:days]; } + (NSDate *) dateWithDaysBeforeNow: (NSInteger) days { // Thanks, Jim Morrison return [[NSDate date] dateBySubtractingDays:days]; } + (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 - String Properties - (NSString *) stringWithFormat: (NSString *) format { NSDateFormatter *formatter = [NSDateFormatter new]; // formatter.locale = [NSLocale currentLocale]; // Necessary? formatter.dateFormat = format; return [formatter stringFromDate:self]; } - (NSString *) stringWithDateStyle: (NSDateFormatterStyle) dateStyle timeStyle: (NSDateFormatterStyle) timeStyle { NSDateFormatter *formatter = [NSDateFormatter new]; formatter.dateStyle = dateStyle; formatter.timeStyle = timeStyle; // formatter.locale = [NSLocale currentLocale]; // Necessary? return [formatter stringFromDate:self]; } - (NSString *) shortString { return [self stringWithDateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterShortStyle]; } - (NSString *) shortTimeString { return [self stringWithDateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterShortStyle]; } - (NSString *) shortDateString { return [self stringWithDateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterNoStyle]; } - (NSString *) mediumString { return [self stringWithDateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterMediumStyle ]; } - (NSString *) mediumTimeString { return [self stringWithDateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterMediumStyle ]; } - (NSString *) mediumDateString { return [self stringWithDateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterNoStyle]; } - (NSString *) longString { return [self stringWithDateStyle:NSDateFormatterLongStyle timeStyle:NSDateFormatterLongStyle ]; } - (NSString *) longTimeString { return [self stringWithDateStyle:NSDateFormatterNoStyle timeStyle:NSDateFormatterLongStyle ]; } - (NSString *) longDateString { return [self stringWithDateStyle:NSDateFormatterLongStyle timeStyle:NSDateFormatterNoStyle]; } #pragma mark - Comparing Dates - (BOOL) isEqualToDateIgnoringTime: (NSDate *) aDate { NSDateComponents *components1 = [[NSDate currentCalendar] components:componentFlags fromDate:self]; NSDateComponents *components2 = [[NSDate currentCalendar] components:componentFlags 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 = [[NSDate currentCalendar] components:componentFlags fromDate:self]; NSDateComponents *components2 = [[NSDate currentCalendar] components:componentFlags 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.weekOfMonth != components2.weekOfMonth) 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]; } // Thanks, mspasov - (BOOL) isSameMonthAsDate: (NSDate *) aDate { NSDateComponents *components1 = [[NSDate currentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth fromDate:self]; NSDateComponents *components2 = [[NSDate currentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth fromDate:aDate]; return ((components1.month == components2.month) && (components1.year == components2.year)); } - (BOOL) isThisMonth { return [self isSameMonthAsDate:[NSDate date]]; } // Thanks Marcin Krzyzanowski, also for adding/subtracting years and months - (BOOL) isLastMonth { return [self isSameMonthAsDate:[[NSDate date] dateBySubtractingMonths:1]]; } - (BOOL) isNextMonth { return [self isSameMonthAsDate:[[NSDate date] dateByAddingMonths:1]]; } - (BOOL) isSameYearAsDate: (NSDate *) aDate { NSDateComponents *components1 = [[NSDate currentCalendar] components:NSCalendarUnitYear fromDate:self]; NSDateComponents *components2 = [[NSDate currentCalendar] components:NSCalendarUnitYear fromDate:aDate]; return (components1.year == components2.year); } - (BOOL) isThisYear { // Thanks, baspellis return [self isSameYearAsDate:[NSDate date]]; } - (BOOL) isNextYear { NSDateComponents *components1 = [[NSDate currentCalendar] components:NSCalendarUnitYear fromDate:self]; NSDateComponents *components2 = [[NSDate currentCalendar] components:NSCalendarUnitYear fromDate:[NSDate date]]; return (components1.year == (components2.year + 1)); } - (BOOL) isLastYear { NSDateComponents *components1 = [[NSDate currentCalendar] components:NSCalendarUnitYear fromDate:self]; NSDateComponents *components2 = [[NSDate currentCalendar] components:NSCalendarUnitYear 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); } // Thanks, markrickert - (BOOL) isInFuture { return ([self isLaterThanDate:[NSDate date]]); } // Thanks, markrickert - (BOOL) isInPast { return ([self isEarlierThanDate:[NSDate date]]); } #pragma mark - Roles - (BOOL) isTypicallyWeekend { NSDateComponents *components = [[NSDate currentCalendar] components:NSCalendarUnitWeekday fromDate:self]; if ((components.weekday == 1) || (components.weekday == 7)) return YES; return NO; } - (BOOL) isTypicallyWorkday { return ![self isTypicallyWeekend]; } #pragma mark - Adjusting Dates // Thaks, rsjohnson - (NSDate *) dateByAddingYears: (NSInteger) dYears { NSDateComponents *dateComponents = [[NSDateComponents alloc] init]; [dateComponents setYear:dYears]; NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:self options:0]; return newDate; } - (NSDate *) dateBySubtractingYears: (NSInteger) dYears { return [self dateByAddingYears:-dYears]; } - (NSDate *) dateByAddingMonths: (NSInteger) dMonths { NSDateComponents *dateComponents = [[NSDateComponents alloc] init]; [dateComponents setMonth:dMonths]; NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:self options:0]; return newDate; } - (NSDate *) dateBySubtractingMonths: (NSInteger) dMonths { return [self dateByAddingMonths:-dMonths]; } // Courtesy of dedan who mentions issues with Daylight Savings - (NSDate *) dateByAddingDays: (NSInteger) dDays { NSDateComponents *dateComponents = [[NSDateComponents alloc] init]; [dateComponents setDay:dDays]; NSDate *newDate = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:self options:0]; 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)]; } - (NSDateComponents *) componentsWithOffsetFromDate: (NSDate *) aDate { NSDateComponents *dTime = [[NSDate currentCalendar] components:componentFlags fromDate:aDate toDate:self options:0]; return dTime; } #pragma mark - Extremes - (NSDate *) dateAtStartOfDay { NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; components.hour = 0; components.minute = 0; components.second = 0; return [[NSDate currentCalendar] dateFromComponents:components]; } // Thanks gsempe & mteece - (NSDate *) dateAtEndOfDay { NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; components.hour = 23; // Thanks Aleksey Kononov components.minute = 59; components.second = 59; return [[NSDate currentCalendar] dateFromComponents:components]; } #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); } // Thanks, dmitrydims // I have not yet thoroughly tested this - (NSInteger)distanceInDaysToDate:(NSDate *)anotherDate { NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian]; NSDateComponents *components = [gregorianCalendar components:NSCalendarUnitDay fromDate:self toDate:anotherDate options:0]; return components.day; } #pragma mark - Decomposing Dates - (NSInteger) nearestHour { NSTimeInterval aTimeInterval = [[NSDate date] timeIntervalSinceReferenceDate] + D_MINUTE * 30; NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval]; NSDateComponents *components = [[NSDate currentCalendar] components:NSCalendarUnitHour fromDate:newDate]; return components.hour; } - (NSInteger) hour { NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; return components.hour; } - (NSInteger) minute { NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; return components.minute; } - (NSInteger) seconds { NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; return components.second; } - (NSInteger) day { NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; return components.day; } - (NSInteger) month { NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; return components.month; } - (NSInteger) week { NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; return components.weekOfMonth; } - (NSInteger) weekday { NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; return components.weekday; } - (NSInteger) nthWeekday // e.g. 2nd Tuesday of the month is 2 { NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; return components.weekdayOrdinal; } - (NSInteger) year { NSDateComponents *components = [[NSDate currentCalendar] components:componentFlags fromDate:self]; return components.year; } + (NSDate *)date:(NSString *)datestr WithFormat:(NSString *)format { NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setLocale:[NSLocale currentLocale]]; [dateFormatter setTimeZone:[NSTimeZone localTimeZone]]; [dateFormatter setDateFormat:format]; NSDate *date = [dateFormatter dateFromString:datestr]; #if ! __has_feature(objc_arc) [dateFormatter release]; #endif return date; } - (NSDate *)dateWithYMD { NSDateFormatter *fmt = [[NSDateFormatter alloc] init]; fmt.dateFormat = @"yyyy-MM-dd"; NSString *selfStr = [fmt stringFromDate:self]; return [fmt dateFromString:selfStr]; } -(NSDate *)dateWithFormatter:(NSString *)formatter { NSDateFormatter *fmt = [[NSDateFormatter alloc] init]; fmt.dateFormat = formatter; NSString *selfStr = [fmt stringFromDate:self]; return [fmt dateFromString:selfStr]; } @end