Search code examples
iosobjective-cnscalendar

dateBySettingUnit method of NSCalendar returns not obvious result


My problem is solved by NSDateComponents, but I want to understand why this method works so

NSDate *today = [NSDate date];
NSLog(@"today is: %@", today);

NSDate *dayChanged = [calendar dateBySettingUnit:(NSCalendarUnitDay)
                                           value:10
                                          ofDate:today
                                         options:0];
NSLog(@"dayChanged is: %@", dayChanged);

NSDate *monthChanged = [calendar dateBySettingUnit:(NSCalendarUnitMonth)
                                             value:5
                                            ofDate:today
                                           options:0];
NSLog(@"monthChanged is: %@", monthChanged);

result is:

today is: 2016-09-30 06:40:36 +0000
dayChanged is: 2016-10-10 00:00:00 +0000
monthChanged is: 2017-05-01 00:00:00 +0000

Why dateBySettingUnit increments next larger unit?


Solution

  • As per the observation, dateBySettingUnit does not return past date

    So for a quick test setting using dateBySettingUnit for future dates works as expected, see below code:

    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSDate *today = [NSDate date];
    NSLog(@"today is: %@", today);
    
    NSDate *dayChanged = [calendar dateBySettingUnit:(NSCalendarUnitDay)
                                               value:31
                                              ofDate:today
                                             options:NSCalendarWrapComponents];
    NSLog(@"dayChanged is: %@", dayChanged);
    
    NSDate *monthChanged = [calendar dateBySettingUnit:(NSCalendarUnitMonth)
                                                 value:12
                                                ofDate:dayChanged
                                               options:NSCalendarWrapComponents];
    NSLog(@"monthChanged is: %@", monthChanged);
    

    Log:

    2016-09-30 12:58:30.506 TestRegex[3785:72957] today is: 2016-09-30 07:58:30 +0000
    2016-09-30 12:58:30.508 TestRegex[3785:72957] dayChanged is: 2016-09-30 19:00:00 +0000
    2016-09-30 12:58:30.509 TestRegex[3785:72957] monthChanged is: 2016-11-30 19:00:00 +0000
    

    You can try the extension for NSCalendar mentioned in the answer of the link which actually calculates the offset or you can use NSDateComponents solution:

     NSDateComponents *comps = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:today];
    [comps setCalendar:calendar];
    [comps setDay:5];
    

    Hope that helps!