使用 Cocoa 确定两个日期之间的月数

发布于 2024-08-05 13:57:21 字数 45 浏览 1 评论 0原文

如何使用 Cocoa 计算两个日期之间的月数?

谢谢, 斯坦

How do I calculate the number of months between two dates using Cocoa?

Thanks,
Stan

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

只有一腔孤勇 2024-08-12 13:57:22

查看 NSCalendars

Look at NSCalendars components:fromDate:toDate:options method. It allows you to subtract dates and then extract the months property value

爱格式化 2024-08-12 13:57:22

要获得包含一个月的一部分的答案,可以使用以下命令:

- (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)]; 
}

To get an answer that includes the fraction of a month the following can be used:

- (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)]; 
}
红焚 2024-08-12 13:57:22

我必须计算两个日期之间的月份变化。这意味着从 1 月 31 日到 2 月 1 日已经过去了 1 个月,NSCalendar.components 将返回 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!")
    }
}

I had to calculate the months changes between two dates. This means that from the 31st of January to the 1st of February 1 month has passed were NSCalendar.components will return 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!")
    }
}
落墨 2024-08-12 13:57:22

对于以下示例,组件:fromDate:toDate:选项无法正常工作:

开始日期:2012 年 1 月 1 日
结束日期:2012 年 3 月 31 日。

使用上述方法的月份数 = 2

正确答案应该是 3 个月。

我使用长计算方式如下:
1. 找出起始月份的天数。将其添加到月份的小数部分。如果第一个日期是月初,则将其计为整月。
2. 求最后一个月的天数。将其添加到月份的小数部分如果日期是该月的最后一天,则将其视为完整月份。
3. 找到 2 个日期之间的整个/完整月份并添加到月份的整数部分。
4. 添加整数 &月份的小数部分以获得正确的值。

components:fromDate:toDate:options doesn't work correctly for following example:

begin date: Jan 01, 2012
end date: March 31, 2012.

num of months using above method = 2

The correct answer should be 3 months.

I am using the long way of calculations as follows:
1. Find number of days in the beginning month. Add it to the fraction part of the month. If the first date is the beginning of the month, count it as full month.
2. find the number of days in the end month. Add it to the fraction part of the monthIf the date is the last of the month count it as a full month.
3. Find the whole/full months between the 2 dates and add to the integer part of the month.
4. Add the integer & fraction parts of the months to get a correct value.

别想她 2024-08-12 13:57:22

这是针对 iOS11 更新的 @eliocs 答案的 Objective-C 版本:

- (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);
}

Here's the objective-c version of @eliocs answer updated for 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);
}
心舞飞扬 2024-08-12 13:57:21
NSInteger month = [[[NSCalendar currentCalendar] components: NSCalendarUnitMonth
                                                   fromDate: yourFirstDate
                                                     toDate: yourSecondDate
                                                    options: 0] month];
NSInteger month = [[[NSCalendar currentCalendar] components: NSCalendarUnitMonth
                                                   fromDate: yourFirstDate
                                                     toDate: yourSecondDate
                                                    options: 0] month];
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文