【问题标题】:Get number of weeks for a given ISO 8601 calendar year获取给定 ISO 8601 日历年的周数
【发布时间】:2023-03-06 15:49:01
【问题描述】:

根据 ISO 周系统 (ISO8601),我需要创建一个函数来快速计算给定年份的周数。我需要这个数字作为 Int。首先,我想我需要为 12 月 31 日制作一个 NSDate 并询问那是在哪一周,然后我意识到有时 12 月 31 日是在下一年的第 1 周(例如 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 周

【问题讨论】:

    标签: swift date calendar nsdate iso8601


    【解决方案1】:

    确定一年中周数的简单公式 ISO日历的可以在Long and Short ISO Calendar Years找到:

    如果满足以下条件,则 ISO 日历年 y 很长(包含 53 周):
    - p(y) 模 7 = 4
    或者如果:
    - p(y–1) 模 7 = 3
    与:
    - p(y) = y + floor(y/4) – floor(y/100) + floor(y/400)

    注意Wikipedia: Weeks per year 中的版本似乎 有一个小错误,“if 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's approach):

    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
    }
    

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

    【讨论】:

      【解决方案2】:

      为 Swift 3 工作:

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

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

      希望对你有帮助!

      【讨论】:

      • 对于 ISO-week-system,您需要 ISO8601 日历 NSCalendar 和单位 .yearForWeekOfYear
      • Vadian,请您看看我在问题中添加的代码,并告诉我 .yearForWeekOfYear 应该在哪里。我在 weekRange-line 的 "of:" 槽和 "in:" 槽中都试过了
      • @KlasZetterlund:应该是in: .yearForWeekOfYear。此外,您不能选择 1 月 1 日作为日期,因为这可能属于上一个 ISO 年份。使用01-02-yyyy 它应该可以工作。
      【解决方案3】:
      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
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-28
        • 1970-01-01
        • 2016-05-02
        • 2015-01-11
        • 2018-01-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多