Determine o número de meses entre duas datas usando cacau
-
18-09-2019 - |
Pergunta
Como calcular o número de meses entre duas datas usando cacau?
Obrigado, Stan
Solução
Olhe para os Nscalendars Componentes: FromDate: Todate: Opções método. Permite subtrair as datas e depois extrair o valor da propriedade dos meses
Outras dicas
NSInteger month = [[[NSCalendar currentCalendar] components: NSCalendarUnitMonth
fromDate: yourFirstDate
toDate: yourSecondDate
options: 0] month];
Para obter uma resposta que inclua a fração de um mês, o seguinte pode ser usado:
- (NSNumber *)numberOfMonthsBetweenFirstDate:(NSDate *)firstDate secondDate:(NSDate *)secondDate {
if ([firstDate compare:secondDate] == NSOrderedDescending) {
return nil;
}
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *firstDateComponents = [calendar components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit
fromDate:firstDate];
NSInteger firstDay = [firstDateComponents day];
NSRange rangeOfFirstMonth = [calendar rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:firstDate];
NSUInteger numberOfDaysInFirstMonth = rangeOfFirstMonth.length;
CGFloat firstMonthFraction = (CGFloat)(numberOfDaysInFirstMonth - firstDay) / (CGFloat)numberOfDaysInFirstMonth;
// last month component
NSDateComponents *lastDateComponents = [calendar components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit
fromDate:secondDate];
NSInteger lastDay = [lastDateComponents day];
NSRange rangeOfLastMonth = [calendar rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:secondDate];
NSUInteger numberOfDaysInLastMonth = rangeOfLastMonth.length;
CGFloat lastMonthFraction = (CGFloat)(lastDay) / (CGFloat)numberOfDaysInLastMonth;
// Check if the two dates are within the same month
if (firstDateComponents.month == lastDateComponents.month
&& firstDateComponents.year == lastDateComponents.year) {
NSDateComponents *dayComponents = [calendar components:NSDayCalendarUnit
fromDate:firstDate
toDate:secondDate
options:0];
NSRange rangeOfMonth = [calendar rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:firstDate];
NSUInteger numberOfDaysInMonth = rangeOfMonth.length;
return [NSNumber numberWithFloat:(CGFloat)dayComponents.day / (CGFloat)numberOfDaysInMonth];
}
// Start date of the first complete month
NSDateComponents *firstDateFirstDayOfNextMonth = firstDateComponents;
firstDateFirstDayOfNextMonth.month +=1;
firstDateFirstDayOfNextMonth.day = 1;
// First day of the last month
NSDateComponents *secondDateFirstDayOfMonth = lastDateComponents;
secondDateFirstDayOfMonth.day = 1;
NSInteger numberOfMonths = secondDateFirstDayOfMonth.month - firstDateFirstDayOfNextMonth.month
+ (secondDateFirstDayOfMonth.year - firstDateFirstDayOfNextMonth.year) * 12;
return [NSNumber numberWithFloat:(firstMonthFraction + numberOfMonths + lastMonthFraction)];
}
Eu tive que calcular as mudanças dos meses entre duas datas. Isso significa que, de 31 de janeiro a 1º de fevereiro, 1 mês se passou foram NSCalendar.components
retornará 0.
import UIKit
func monthsSince(from: NSDate, to: NSDate) -> Int {
let fromComponents = NSCalendar.currentCalendar().components([.Month, .Year], fromDate: from)
let toComponents = NSCalendar.currentCalendar().components([.Month, .Year], fromDate: to)
return ((toComponents.year - fromComponents.year) * 12) + (toComponents.month - fromComponents.month)
}
let tests = [
(from: (day: 1, month: 1, year: 2016), to: (day: 31, month: 1, year: 2016), result: 0),
(from: (day: 22, month: 1, year: 2016), to: (day: 5, month: 2, year: 2016), result: 1),
(from: (day: 22, month: 12, year: 2015), to: (day: 1, month: 1, year: 2016), result: 1),
(from: (day: 1, month: 1, year: 2016), to: (day: 1, month: 2, year: 2016), result: 1),
(from: (day: 1, month: 1, year: 2016), to: (day: 1, month: 3, year: 2016), result: 2)
]
for test in tests {
let from = NSCalendar.currentCalendar().dateWithEra(1, year: test.from.year, month: test.from.month, day: test.from.day, hour: 0, minute: 0, second: 0, nanosecond: 0)!
let to = NSCalendar.currentCalendar().dateWithEra(1, year: test.to.year, month: test.to.month, day: test.to.day, hour: 0, minute: 0, second: 0, nanosecond: 0)!
if monthsSince(from, to: to) == test.result {
print("Test \(test), Passed!")
} else {
print("Test \(test), Failed!")
}
}
Componentes: FromDate: Todate: Opções não funciona corretamente para o seguinte exemplo:
Data de início: 01 de janeiro de 2012 Data de término: 31 de março de 2012.
Número de meses usando o método acima = 2
A resposta correta deve ser de 3 meses.
Estou usando o longo caminho de cálculos da seguinte forma: 1. Encontre o número de dias no mês inicial. Adicione -o à parte da fração do mês. Se a primeira data for o início do mês, conte -a como mês inteiro. 2. Encontre o número de dias no final do mês. Adicione -o à parte da fração do mês, se a data for a última conta do mês como um mês inteiro. 3. Encontre os meses inteiros/completos entre as 2 datas e adicione à parte inteira do mês. 4. Adicione as partes do número inteiro e da fração dos meses para obter um valor correto.
Aqui está a versão Objective-C do @Eliocs Resposta atualizada para iOS11:
- (NSInteger)monthsSince:(NSDate *)from to:(NSDate *)to {
NSDateComponents *fromComponents = [[NSCalendar currentCalendar] components:NSCalendarUnitMonth | NSCalendarUnitYear fromDate:from];
NSDateComponents *toComponents = [[NSCalendar currentCalendar] components:NSCalendarUnitMonth | NSCalendarUnitYear fromDate:to];
return ((toComponents.year - fromComponents.year) * 12) + (toComponents.month - fromComponents.month);
}