//
//  NSDate+Extension.m
//  JKCategories (https://github.com/shaojiankui/JKCategories)
//
//  Created by Jakey on 15/4/25.
//  Copyright (c) 2015年 www.skyfox.org. All rights reserved.
//  https://github.com/632840804/HYBNSDateExtension

#import "NSDate+JKExtension.h"

@implementation NSDate (JKExtension)

- (NSUInteger)jk_day {
    return [NSDate jk_day:self];
}

- (NSUInteger)jk_month {
    return [NSDate jk_month:self];
}

- (NSUInteger)jk_year {
    return [NSDate jk_year:self];
}

- (NSUInteger)jk_hour {
    return [NSDate jk_hour:self];
}

- (NSUInteger)jk_minute {
    return [NSDate jk_minute:self];
}

- (NSUInteger)jk_second {
    return [NSDate jk_second:self];
}

+ (NSUInteger)jk_day:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
    // NSDayCalendarUnit
    NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitDay) fromDate:date];
#else
    NSDateComponents *dayComponents = [calendar components:(NSDayCalendarUnit) fromDate:date];
#endif
    
    return [dayComponents day];
}

+ (NSUInteger)jk_month:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
    // NSDayCalendarUnit
    NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitMonth) fromDate:date];
#else
    NSDateComponents *dayComponents = [calendar components:(NSMonthCalendarUnit) fromDate:date];
#endif
    
    return [dayComponents month];
}

+ (NSUInteger)jk_year:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
    // NSDayCalendarUnit
    NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitYear) fromDate:date];
#else
    NSDateComponents *dayComponents = [calendar components:(NSYearCalendarUnit) fromDate:date];
#endif
    
    return [dayComponents year];
}

+ (NSUInteger)jk_hour:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
    // NSDayCalendarUnit
    NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitHour) fromDate:date];
#else
    NSDateComponents *dayComponents = [calendar components:(NSHourCalendarUnit) fromDate:date];
#endif
    
    return [dayComponents hour];
}

+ (NSUInteger)jk_minute:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
    // NSDayCalendarUnit
    NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitMinute) fromDate:date];
#else
    NSDateComponents *dayComponents = [calendar components:(NSMinuteCalendarUnit) fromDate:date];
#endif
    
    return [dayComponents minute];
}

+ (NSUInteger)jk_second:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
    // NSDayCalendarUnit
    NSDateComponents *dayComponents = [calendar components:(NSCalendarUnitSecond) fromDate:date];
#else
    NSDateComponents *dayComponents = [calendar components:(NSSecondCalendarUnit) fromDate:date];
#endif
    
    return [dayComponents second];
}

- (NSUInteger)jk_daysInYear {
    return [NSDate jk_daysInYear:self];
}

+ (NSUInteger)jk_daysInYear:(NSDate *)date {
    return [self jk_isLeapYear:date] ? 366 : 365;
}

- (NSTimeInterval)by_timeIntervalWithDate:(NSDate *)date{
    return [self timeIntervalSinceDate:date];
}


- (BOOL)jk_isLeapYear {
    return [NSDate jk_isLeapYear:self];
}

+ (BOOL)jk_isLeapYear:(NSDate *)date {
    NSUInteger year = [date jk_year];
    if ((year % 4  == 0 && year % 100 != 0) || year % 400 == 0) {
        return YES;
    }
    return NO;
}

- (NSString *)jk_formatYMD {
    return [NSDate jk_formatYMD:self];
}

+ (NSString *)jk_formatYMD:(NSDate *)date {
    return [NSString stringWithFormat:@"%lu-%02lu-%02lu",(unsigned long)[date jk_year],(unsigned long)[date jk_month], (unsigned long)[date jk_day]];
}

- (NSUInteger)jk_weeksOfMonth {
    return [NSDate jk_weeksOfMonth:self];
}

+ (NSUInteger)jk_weeksOfMonth:(NSDate *)date {
    return [[date jk_lastdayOfMonth] jk_weekOfYear] - [[date jk_begindayOfMonth] jk_weekOfYear] + 1;
}

- (NSUInteger)jk_weekOfYear {
    return [NSDate jk_weekOfYear:self];
}

+ (NSUInteger)jk_weekOfYear:(NSDate *)date {
    NSUInteger i;
    NSUInteger year = [date jk_year];
    
    NSDate *lastdate = [date jk_lastdayOfMonth];
    
    for (i = 1;[[lastdate jk_dateAfterDay:-7 * i] jk_year] == year; i++) {
        
    }
    
    return i;
}

- (NSDate *)jk_dateAfterDay:(NSUInteger)day {
    return [NSDate jk_dateAfterDate:self day:day];
}

+ (NSDate *)jk_dateAfterDate:(NSDate *)date day:(NSInteger)day {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *componentsToAdd = [[NSDateComponents alloc] init];
    [componentsToAdd setDay:day];
    
    NSDate *dateAfterDay = [calendar dateByAddingComponents:componentsToAdd toDate:date options:0];
    
    return dateAfterDay;
}

- (NSDate *)jk_dateAfterMonth:(NSUInteger)month {
    return [NSDate jk_dateAfterDate:self month:month];
}

+ (NSDate *)jk_dateAfterDate:(NSDate *)date month:(NSInteger)month {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *componentsToAdd = [[NSDateComponents alloc] init];
    [componentsToAdd setMonth:month];
    NSDate *dateAfterMonth = [calendar dateByAddingComponents:componentsToAdd toDate:date options:0];
    
    return dateAfterMonth;
}

- (NSDate *)jk_begindayOfMonth {
    return [NSDate jk_begindayOfMonth:self];
}

+ (NSDate *)jk_begindayOfMonth:(NSDate *)date {
    return [self jk_dateAfterDate:date day:-[date jk_day] + 1];
}

- (NSDate *)jk_lastdayOfMonth {
    return [NSDate jk_lastdayOfMonth:self];
}

+ (NSDate *)jk_lastdayOfMonth:(NSDate *)date {
    NSDate *lastDate = [self jk_begindayOfMonth:date];
    return [[lastDate jk_dateAfterMonth:1] jk_dateAfterDay:-1];
}

- (NSUInteger)jk_daysAgo {
    return [NSDate jk_daysAgo:self];
}

+ (NSUInteger)jk_daysAgo:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
    NSDateComponents *components = [calendar components:(NSCalendarUnitDay)
                                               fromDate:date
                                                 toDate:[NSDate date]
                                                options:0];
#else
    NSDateComponents *components = [calendar components:(NSDayCalendarUnit)
                                               fromDate:date
                                                 toDate:[NSDate date]
                                                options:0];
#endif
    
    return [components day];
}

- (NSInteger)jk_weekday {
    return [NSDate jk_weekday:self];
}

+ (NSInteger)jk_weekday:(NSDate *)date {
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSDateComponents *comps = [gregorian components:(NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear | NSCalendarUnitWeekday) fromDate:date];
    NSInteger weekday = [comps weekday];
    
    return weekday;
}

- (NSString *)jk_dayFromWeekday {
    return [NSDate jk_dayFromWeekday:self];
}

+ (NSString *)jk_dayFromWeekday:(NSDate *)date {
    switch([date jk_weekday]) {
        case 1:
            return @"星期天";
            break;
        case 2:
            return @"星期一";
            break;
        case 3:
            return @"星期二";
            break;
        case 4:
            return @"星期三";
            break;
        case 5:
            return @"星期四";
            break;
        case 6:
            return @"星期五";
            break;
        case 7:
            return @"星期六";
            break;
        default:
            break;
    }
    return @"";
}

- (BOOL)jk_isSameDay:(NSDate *)anotherDate {
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *components1 = [calendar components:(NSCalendarUnitYear
                                                          | NSCalendarUnitMonth
                                                          | NSCalendarUnitDay)
                                                fromDate:self];
    NSDateComponents *components2 = [calendar components:(NSCalendarUnitYear
                                                          | NSCalendarUnitMonth
                                                          | NSCalendarUnitDay)
                                                fromDate:anotherDate];
    return ([components1 year] == [components2 year]
            && [components1 month] == [components2 month]
            && [components1 day] == [components2 day]);
}

- (BOOL)jk_isToday {
    return [self jk_isSameDay:[NSDate date]];
}

- (NSDate *)jk_dateByAddingDays:(NSUInteger)days {
    NSDateComponents *c = [[NSDateComponents alloc] init];
    c.day = days;
    return [[NSCalendar currentCalendar] dateByAddingComponents:c toDate:self options:0];
}

/**
 *  Get the month as a localized string from the given month number
 *
 *  @param month The month to be converted in string
 *  [1 - January]
 *  [2 - February]
 *  [3 - March]
 *  [4 - April]
 *  [5 - May]
 *  [6 - June]
 *  [7 - July]
 *  [8 - August]
 *  [9 - September]
 *  [10 - October]
 *  [11 - November]
 *  [12 - December]
 *
 *  @return Return the given month as a localized string
 */
+ (NSString *)jk_monthWithMonthNumber:(NSInteger)month {
    switch(month) {
        case 1:
            return @"January";
            break;
        case 2:
            return @"February";
            break;
        case 3:
            return @"March";
            break;
        case 4:
            return @"April";
            break;
        case 5:
            return @"May";
            break;
        case 6:
            return @"June";
            break;
        case 7:
            return @"July";
            break;
        case 8:
            return @"August";
            break;
        case 9:
            return @"September";
            break;
        case 10:
            return @"October";
            break;
        case 11:
            return @"November";
            break;
        case 12:
            return @"December";
            break;
        default:
            break;
    }
    return @"";
}

+ (NSString *)jk_stringWithDate:(NSDate *)date format:(NSString *)format {
    return [date jk_stringWithFormat:format];
}

- (NSString *)jk_stringWithFormat:(NSString *)format {
    NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
    [outputFormatter setDateFormat:format];
    [outputFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:8*3600]];
    NSString *retStr = [outputFormatter stringFromDate:self];
    
    return retStr;
}

+ (NSDate *)jk_dateWithString:(NSString *)string format:(NSString *)format {
    NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
    [inputFormatter setDateFormat:format];
    NSDate *date = [inputFormatter dateFromString:string];
    
    return date;
}

- (NSUInteger)jk_daysInMonth:(NSUInteger)month {
    return [NSDate jk_daysInMonth:self month:month];
}

+ (NSUInteger)jk_daysInMonth:(NSDate *)date month:(NSUInteger)month {
    switch (month) {
        case 1: case 3: case 5: case 7: case 8: case 10: case 12:
            return 31;
        case 2:
            return [date jk_isLeapYear] ? 29 : 28;
    }
    return 30;
}

- (NSUInteger)jk_daysInMonth {
    return [NSDate jk_daysInMonth:self];
}

+ (NSUInteger)jk_daysInMonth:(NSDate *)date {
    return [self jk_daysInMonth:date month:[date jk_month]];
}

- (NSString *)jk_timeInfo {
    return [NSDate jk_timeInfoWithDate:self];
}

+ (NSString *)jk_timeInfoWithDate:(NSDate *)date {
    return [self jk_timeInfoWithDateString:[self jk_stringWithDate:date format:[self jk_ymdHmsFormat]]];
}

+ (NSString *)jk_timeInfoWithDateString:(NSString *)dateString {
    NSDate *date = [self jk_dateWithString:dateString format:[self jk_ymdHmsFormat]];
    
    NSDate *curDate = [NSDate date];
    NSTimeInterval time = -[date timeIntervalSinceDate:curDate];
    
    int month = (int)([curDate jk_month] - [date jk_month]);
    int year = (int)([curDate jk_year] - [date jk_year]);
    int day = (int)([curDate jk_day] - [date jk_day]);
    
    NSTimeInterval retTime = 1.0;
    if (time < 3600) { // 小于一小时
        retTime = time / 60;
        retTime = retTime <= 0.0 ? 1.0 : retTime;
        return [NSString stringWithFormat:@"%.0f分钟前", retTime];
    } else if (time < 3600 * 24) { // 小于一天,也就是今天
        retTime = time / 3600;
        retTime = retTime <= 0.0 ? 1.0 : retTime;
        return [NSString stringWithFormat:@"%.0f小时前", retTime];
    } else if (time < 3600 * 24 * 2) {
        return @"昨天";
    }
    // 第一个条件是同年,且相隔时间在一个月内
    // 第二个条件是隔年,对于隔年,只能是去年12月与今年1月这种情况
    else if ((abs(year) == 0 && abs(month) <= 1)
             || (abs(year) == 1 && [curDate jk_month] == 1 && [date jk_month] == 12)) {
        int retDay = 0;
        if (year == 0) { // 同年
            if (month == 0) { // 同月
                retDay = day;
            }
        }
        
        if (retDay <= 0) {
            // 获取发布日期中,该月有多少天
            int totalDays = (int)[self jk_daysInMonth:date month:[date jk_month]];
            
            // 当前天数 + (发布日期月中的总天数-发布日期月中发布日,即等于距离今天的天数)
            retDay = (int)[curDate jk_day] + (totalDays - (int)[date jk_day]);
        }
        
        return [NSString stringWithFormat:@"%d天前", (abs)(retDay)];
    } else  {
        if (abs(year) <= 1) {
            if (year == 0) { // 同年
                return [NSString stringWithFormat:@"%d个月前", abs(month)];
            }
            
            // 隔年
            int month = (int)[curDate jk_month];
            int preMonth = (int)[date jk_month];
            if (month == 12 && preMonth == 12) {// 隔年,但同月,就作为满一年来计算
                return @"1年前";
            }
            return [NSString stringWithFormat:@"%d个月前", (abs)(12 - preMonth + month)];
        }
        
        return [NSString stringWithFormat:@"%d年前", abs(year)];
    }
    
    return @"1小时前";
}

- (NSString *)jk_ymdFormat {
    return [NSDate jk_ymdFormat];
}

- (NSString *)jk_hmsFormat {
    return [NSDate jk_hmsFormat];
}

- (NSString *)jk_ymdHmsFormat {
    return [NSDate jk_ymdHmsFormat];
}

+ (NSString *)jk_ymdFormat {
    return @"yyyy-MM-dd";
}

+ (NSString *)jk_hmsFormat {
    return @"HH:mm:ss";
}

+ (NSString *)jk_ymdHmsFormat {
    return [NSString stringWithFormat:@"%@ %@", [self jk_ymdFormat], [self jk_hmsFormat]];
}

- (NSDate *)jk_offsetYears:(int)numYears {
    return [NSDate jk_offsetYears:numYears fromDate:self];
}

+ (NSDate *)jk_offsetYears:(int)numYears fromDate:(NSDate *)fromDate {
    if (fromDate == nil) {
        return nil;
    }
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
    // NSDayCalendarUnit
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
#else
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSGregorianCalendar];
#endif
    
    
    NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
    [offsetComponents setYear:numYears];
    
    return [gregorian dateByAddingComponents:offsetComponents
                                      toDate:fromDate
                                     options:0];
}

- (NSDate *)jk_offsetMonths:(int)numMonths {
    return [NSDate jk_offsetMonths:numMonths fromDate:self];
}

+ (NSDate *)jk_offsetMonths:(int)numMonths fromDate:(NSDate *)fromDate {
    if (fromDate == nil) {
        return nil;
    }
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
    // NSDayCalendarUnit
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
#else
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSGregorianCalendar];
#endif
    
    
    NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
    [offsetComponents setMonth:numMonths];
    
    return [gregorian dateByAddingComponents:offsetComponents
                                      toDate:fromDate
                                     options:0];
}

- (NSDate *)jk_offsetDays:(int)numDays {
    return [NSDate jk_offsetDays:numDays fromDate:self];
}

+ (NSDate *)jk_offsetDays:(int)numDays fromDate:(NSDate *)fromDate {
    if (fromDate == nil) {
        return nil;
    }
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
    // NSDayCalendarUnit
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
#else
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSGregorianCalendar];
#endif
    
    
    NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
    [offsetComponents setDay:numDays];
    
    return [gregorian dateByAddingComponents:offsetComponents
                                      toDate:fromDate
                                     options:0];
}

- (NSDate *)jk_offsetHours:(int)hours {
    return [NSDate jk_offsetHours:hours fromDate:self];
}

+ (NSDate *)jk_offsetHours:(int)numHours fromDate:(NSDate *)fromDate {
    if (fromDate == nil) {
        return nil;
    }
    
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0
    // NSDayCalendarUnit
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
#else
    NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSGregorianCalendar];
#endif
    
    
    NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
    [offsetComponents setHour:numHours];
    
    return [gregorian dateByAddingComponents:offsetComponents
                                      toDate:fromDate
                                     options:0];
}
@end