Intereting Posts
UITableview меняет высоту, когда отображается с разных UINavigationControllers («Больше») startFirstResponder: автоматически прокручивается до UIControl, который становится первым ответчиком Сделайте снимок и установите его в UIImageView в iOS Получите UITextField из UIView, используя идентификатор / тег (SWIFT) Как ввести небольшую задержку в UIView? Завершение приложения: не удалось загрузить NIB в пакете: «NSBundle …» с именем «7bK-jq-Zjz-view-r7i-6Z-zg0» Обработка изображений в Ios Пользовательский UitableViewCell показывает повторяющиеся данные для некоторых строк таблицы Обнаруживать, подключена ли гарнитура – iOS 5 Получать данные до и после тире (-) в строке JSON? Как найти две опорные точки в iOS8 для внутренней карты? Отклонить порожденные взгляды детей на UIActivityViewController Почему NSMutableSet может быть добавлено больше объектов, чем емкость Beacon не открывает iOS Xcode 8.1 Выберите начальный вид устройства, отображающий только iPhone 7 и 7s

Окно 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];