获取给定ISO 8601日历年的周数



我需要根据ISO-week-system (ISO8601)创建一个函数,用于在swift中计算给定年份的周数。我需要这个数字是整型的。首先,我认为我需要为12月31日创建一个NSDate,并询问它在哪一周,然后我意识到有时12月31日在次年的第一周(例如2014年12月31日)有人知道怎么做吗?

我试着

var calendarr = NSCalendar(calendarIdentifier: NSCalendar.Identifier.ISO8601)!
var monday = "01-01-2005"
var dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"
var datumet = dateFormatter.date(from: monday)
var weekRange = calendarr.range(of: .weekOfYear, in: .year, for: datumet!)
var weeksCount = weekRange.length
print("this many weeks", weeksCount)

但它给了我53周,不管我投入哪一年。作为参考,2004年是53周,2005年是52周

一个简单的公式,用于确定一年中的周数可在ISO历年长、短中找到:

如果满足以下条件,则ISO日历年y很长(包含53周):

  • p(y)模7 = 4
    或者:
  • p(y-1)模7 = 3
    :
  • p (y) = y +地板(y/4) - (y/100) +楼(y/400)

请注意维基百科的版本:每年几周似乎如果p(year) = 5"应该是"if p(year) = 4"

这是Swift中的一个实现:

func weeks(in year: Int) -> Int {
    func p(_ year: Int) -> Int {
        return (year + year/4 - year/100 + year/400) % 7
    }
    return (p(year) == 4 || p(year-1) == 3) ? 53 : 52
}
测试:

print(weeks(in: 2015)) // 53
print(weeks(in: 2016)) // 52
let longYears = (2000...2100).filter({ weeks(in: $0) == 53 })
print(longYears)
// [2004, 2009, 2015, 2020, 2026, 2032, 2037, 2043, 2048, 2054, 2060, 2065, 2071, 2076, 2082, 2088, 2093, 2099]

与维基百科文章中给出的列表一致。


重新编辑:您尝试的代码几乎是正确的。正如@vadian在评论中所说,它应该是

let weekRange = calendarr.range(of: .weekOfYear, in: .yearForWeekOfYear, for: datumet!)

此外,1月1日可能属于上一个 ISO年(例如2016年)。在给定年份的1月4日至12月28日之间选择任何一天都可以解决这个问题。

通过一些进一步的简化得到如下方法(基于Kevin Sabbe的方法):

func weeks(in year: Int) -> Int {
    let cal = Calendar(identifier: .iso8601)
    let date = DateComponents(calendar: cal, year: year, month: 2, day: 1).date!
    let weeksRange = cal.range(of: .weekOfYear, in: .yearForWeekOfYear, for: date)!
    return weeksRange.count
}

,产生与上面函数相同的结果。

附录:正如@Olex在评论中建议的那样,这甚至更好("没有神奇的数字'2',并且保持'一年中的一周'计算范式"):

func weeks(in year: Int) -> Int {
    let cal = Calendar(identifier: .iso8601)
    let date = DateComponents(calendar: cal, weekday: 1, weekOfYear: 1, yearForWeekOfYear: year).date!
    let weeksRange = cal.range(of: .weekOfYear, in: .yearForWeekOfYear, for: date)!
    return weeksRange.count
}

Work for Swift 3:

let weekRange = NSCalendar.current.range(of: .weekOfYear, in: .yearForWeekOfYear, for: Date())
print("(weekRange?.count)")

您必须在Date()中指定年份,它将为您提供全年的周数。

我希望它有帮助!

import Foundation
extension Date {
    
    var lastDayOfMonth: Date {
        return set(dayOfMonth: Calendar.autoupdatingCurrent.range(of: .day, in: .month, for: self)!.count)
    }
    
    func set(dayOfMonth: Int) -> Date {
        let calendar = Calendar.autoupdatingCurrent
        var components = calendar.dateComponents([.month, .year], from: self)
        components.day = dayOfMonth
        return calendar.date(from: components)!
    }
    
    func set(month: Int) -> Date {
        let calendar = Calendar.autoupdatingCurrent
        var components = calendar.dateComponents([.year], from: self)
        components.month = month
        return calendar.date(from: components)!
    }
    
    var weekNumber: Int {
        return Calendar.autoupdatingCurrent.component(.weekOfYear, from: self)
    }
    
    var numberOfWeeksInYear: Int {
        let weekNumber = set(month: 12).lastDayOfMonth.weekNumber
        return weekNumber == 1 ? 52 : weekNumber
    }
}

最新更新