Окно NSDateComponent

Я хочу показать количество месяцев с объекта NSDate.

//Make Date Six Months In The Future NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *sixMonthsFromNow = [[NSDateComponents alloc] init]; [sixMonthsFromNow setMonth:6]; NSDate *finishDate = [calendar dateByAddingComponents:sixMonthsFromNow toDate:[NSDate date] options:0]; //Six Months Time //Display NSCalendarUnit requiredFormat = NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit; NSDateComponents *dateComponents = [calendar components:requiredFormat fromDate:[NSDate date] toDate:finishDate options:0]; NSLog(@"%d months %d days %d hours %d minutes %d seconds", [dateComponents month], [dateComponents day], [dateComponents hour], [dateComponents minute], [dateComponents second]); 

Эти выходы: 5 months 29 days 23 hours 59 minutes 59 seconds

Это здорово, но я хочу показать только количество месяцев.

Если я ограничусь только месяцами:

 //Make Date Six Months In The Future NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents *sixMonthsFromNow = [[NSDateComponents alloc] init]; [sixMonthsFromNow setMonth:6]; NSDate *finishDate = [calendar dateByAddingComponents:sixMonthsFromNow toDate:[NSDate date] options:0]; //Six Months Time //Display NSCalendarUnit requiredFormat = NSMonthCalendarUnit; NSDateComponents *dateComponents = [calendar components:requiredFormat fromDate:[NSDate date] toDate:finishDate options:0]; NSLog(@"%d months", [dateComponents month]); 

Эти результаты: 5 months

Хотя это технически правильно, я хотел бы округлить количество дней, чтобы сделать его выходным на шесть месяцев.

Есть ли простой способ добиться этого эффекта? Я заметил, что на NSDateComponents не было свойства округления. Должен ли я вручную проверить количество дней и решить округлить?

Моя конечная цель – не только ограничить эффект округления до нескольких месяцев, но и иметь возможность округлять часы до нескольких дней, если я только NSDayCalendarUnit : NSDayCalendarUnit

Следующий способ может быть таким, какой вы хотите. Идея состоит в том, что после вычисления (округленного) количества единиц календаря между датой начала и конечной датой добавьте как эту сумму, так и еще одну к дате начала и проверьте, какая из них ближе к дате окончания:

 @interface NSCalendar (MyCategory) -(NSInteger)roundedUnit:(NSCalendarUnit)unit fromDate:(NSDate *)fromDate toDate:(NSDate *)toDate; @end @implementation NSCalendar (MyCategory) -(NSInteger)roundedUnit:(NSCalendarUnit)unit fromDate:(NSDate *)fromDate toDate:(NSDate *)toDate { // Number of units between the two dates: NSDateComponents *comps = [self components:unit fromDate:fromDate toDate:toDate options:0]; NSInteger value = [comps valueForComponent:unit]; // Add (value) units to fromDate: NSDate *date1 = [self dateByAddingComponents:comps toDate:fromDate options:0]; // Add (value + 1) units to fromDate: [comps setValue:(value + 1) forComponent:unit]; NSDate *date2 = [self dateByAddingComponents:comps toDate:fromDate options:0]; // Now date1 <= toDate < date2. Check which one is closer, // and return the corresponding value: NSTimeInterval diff1 = [toDate timeIntervalSinceDate:date1]; NSTimeInterval diff2 = [date2 timeIntervalSinceDate:toDate]; return (diff1 <= diff2 ? value : value + 1); } @end 

И вы будете использовать его как

 NSInteger months = [calendar roundedUnit:NSMonthCalendarUnit fromDate:[NSDate date] toDate:finishDate]; 

В коде используются служебные методы для NSDateComponents из https://github.com/henrinormak/NSDateComponents-HNExtensions/blob/master/README.md :

 - (void)setValue:(NSInteger)value forComponent:(NSCalendarUnit)unit; - (NSInteger)valueForComponent:(NSCalendarUnit)unit; 

Эти методы новы в OS X 10.9, но недоступны в iOS 7.

Как заметил другой комментатор, вы дважды вызываете NSDate, а вторая дата немного позже первой. Используйте один и тот же объект даты дважды, и вы не получите ошибок округления.

Что касается раунда:

Я не думаю, что есть округление, встроенное в календарные методы расчета NSCalendars.

Вам нужно решить, что это значит для вас. Вы можете обойтись на полпути. В этом случае вы можете задать календарь, сколько дней в текущем месяце, используя метод rangeOfUnit: inUnit: forDate, а затем добавить половину этого количества дней до конечной даты, а затем запросить месяц. Если вы хотите «округлить» в течение недели, добавьте только неделю до конца, прежде чем задавать количество разниц в месяцах.

У меня есть аналогичная проблема:

 let fmt1 = NSDateComponentsFormatter() fmt1.allowedUnits = .CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay let dc1 = NSDateComponents() dc1.month = 1 dc1.day = 15 // This occasionally outputs "1 month, 14 days" instead of // "1 month, 15 days" when the formatter is constrained to // years, months and days. If formatter is allowed to use // all units, the output is "1 month, 14 days, 23 hours, // 59 minutes, 59 seconds". fmt1.stringFromDateComponents(dc1) 

Это можно исправить, указав положительное количество секунд и объединив его с установкой параметра maximumUnitCount значенияUnitCount на фиксированное значение:

 let fmt2 = NSDateComponentsFormatter() fmt2.allowedUnits = .CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay fmt2.maximumUnitCount = 2 fmt2.collapsesLargestUnit = true let dc2 = NSDateComponents() dc2.month = 1 dc2.day = 15 dc2.second = 10 // This always outputs "1 month, 15 days" fmt2.stringFromDateComponents(dc2) 

Это исправление, вероятно, будет работать и в вашем случае: просто назначьте некоторое количество секунд NSDateComponents перед вызовом dateByAddingComponents :

 [sixMonthsFromNow setMonth: 6]; [sixMonthsFromNow setSecond: 10];