【问题标题】:number of calendarweeks for year (ISO 8601 definition)一年的日历周数(ISO 8601 定义)
【发布时间】:2012-03-13 22:55:10
【问题描述】:

如何计算给定年份 Objective-C 中的日历周数。

我试过了:

[calendar rangeOfUnit:NSWeekOfYearCalendarUnit inUnit: NSYearCalendarUnit forDate: [NSDate date]].length

但它返回 54。

谢谢

【问题讨论】:

  • 为什么你认为54是错的?
  • 因为年份有 52 或 53 个日历周。 2012 年有 52 个日历周。
  • 这听起来取决于日历周的定义。 366 天是 52 周零 2 天。如果这 2 天分别位于不同的逻辑周,则加起来为 54。也就是说,如果一周从星期一开始,2012 年肯定有 54 周。
  • 啊我明白了。更准确地说,我想要 ISO 8601 中定义的日历周数。

标签: objective-c ios ios5 nscalendar


【解决方案1】:

您使用的是NSWeekOfYearCalendarUnit,因此您必须使用相应的较大单位NSYearForWeekOfYearCalendarUnit

NSCalendar *calendar = [NSCalendar currentCalendar];
calendar.firstWeekday = 2;
calendar.minimumDaysInFirstWeek = 4;
int n = [calendar rangeOfUnit:NSWeekOfYearCalendarUnit inUnit:NSYearForWeekOfYearCalendarUnit forDate: [NSDate date]].length;
NSLog(@"%d", n); // 52

最后,请注意NSWeekOfYearCalendarUnitNSYearForWeekOfYearCalendarUnit 仅适用于 iOS 5.0 和 OS X 10.7。

编辑

正如@lnafziger 所指出的,如果您使用的日期位于上一年或明年的日历周内,例如 2016 年 1 月 1 日,这将计算该年的周数(示例中为 2015 ),而不是日期的实际年份(示例中为 2016 年)。如果这不是您想要的,您可以按如下方式更改日期:

NSDateComponents *components = [calendar components:NSYearCalendarUnit fromDate:date];
components.month = 3;
date = [calendar dateFromComponents:components];

【讨论】:

  • 好的。但是如何计算 ISO 8601 中定义的日历周数
  • 工作正常,tnx -- 是否可以将 forDate: 参数设置为相应年份中的任何日期,例如: NSDateComponents *comp = [[NSDateComponents alloc] init];comp.year=year;comp.month=2; NSDate *aDay =[cal dateFromComponents:comp]; calendarWeekInYear = [cal rangeOfUnit:NSWeekOfYearCalendarUnit inUnit: NSYearForWeekOfYearCalendarUnit forDate:aDay].length;
  • 这有两个问题:1)虽然它恰好在 2012 年是正确的,但在其他许多年它都不起作用(2015 年将是下一个不正确的年份)。这可以通过添加以下两行来解决:[calendar setFirstWeekday:2]; [calendar setMinimumDaysInFirstWeek:4]; 2) 如果您选择“正式”年初之前的日期(对于 8601 日历),它将计算上一年的正确值。即在 2013 年,一年中的第一周从 7 日开始,如果您计算 2013 年 1 月 5 日的日期,它将返回 2012 年的值(该日期所属的年份)。
  • 请注意,问题 #2 可能是可取的,因为 2013 年 1 月 5 日在技术上是 2012 年第 52 周的一部分,但如果没有正确记录,可能会造成混淆。
  • @lnafziger - 好的,谢谢。我忘了添加这两行(我已经看到 OP 在他的previous question 中确实使用了它们)。
【解决方案2】:

经过大量测试,这里有一个函数可以返回任何年份:

- (NSUInteger)iso8601WeeksForYear:(NSUInteger)year {
    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSDateComponents *firstThursdayOfYearComponents = [[NSDateComponents alloc] init];
    [firstThursdayOfYearComponents setWeekday:5]; // Thursday
    [firstThursdayOfYearComponents setWeekdayOrdinal:1]; // The first Thursday of the month
    [firstThursdayOfYearComponents setMonth:1]; // January
    [firstThursdayOfYearComponents setYear:year];
    NSDate *firstThursday = [calendar dateFromComponents:firstThursdayOfYearComponents];

    NSDateComponents *lastDayOfYearComponents = [[NSDateComponents alloc] init];
    [lastDayOfYearComponents setDay:31];
    [lastDayOfYearComponents setMonth:12];
    [lastDayOfYearComponents setYear:year];
    NSDate *lastDayOfYear = [calendar dateFromComponents:lastDayOfYearComponents];

    NSDateComponents *result = [calendar components:NSWeekCalendarUnit fromDate:firstThursday toDate:lastDayOfYear options:0];

    return result.week + 1;
}

基本上,根据规范,总周数与一年中星期四的总数相同,这是计算出来的。

我已经测试了整个 400 年的周期(从 0 年和 2000 年开始)并且所有案例都符合规范。

【讨论】:

  • 我有 [cal setFirstWeekday:2]; [cal setMinimumDaysInFirstWeek:4];包括这是 ISO 定义并得到 54。如果我只包括 [cal setMinimumDaysInFirstWeek:4],如你所料,我得到 53,但正确的数字是 2012 年的 52。
  • 好吧,setFirstWeekday 应该是 5(星期四)
  • 为什么是 5(星期四)? ISO 中的第一个工作日是 1(星期一)。
  • 嗯,我在想,因为它算星期四,并错误地认为这是一周的开始。我做了更多的研究并在上面发布了正确的答案。希望这会有所帮助!
猜你喜欢
  • 2023-03-06
  • 2012-03-28
  • 1970-01-01
  • 2016-05-02
  • 1970-01-01
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多