【问题标题】:Calculate number of weeks in a given month - Swift计算给定月份的周数 - Swift
【发布时间】:2019-05-25 19:21:31
【问题描述】:

查看了一些关于 SO 的不同建议后,我无法确定为什么下面的功能不起作用。它似乎在某些月份返回 6,而在其他月份返回 5。当将星期更改为几天时,它可以完美地工作。

例如,尝试

weeksInMonth(8, forYear 2015) 

结果为 6。

我相信我对日历上的“firstWeekday”属性有什么误解,但苹果或网上没有找到充分的解释。

已尝试过 .WeekOfMonth 和 .WeekOfYear。再次找不到确切差异的解释。

非常欢迎任何建议。

func weeksInMonth(month: Int, forYear year: Int) -> Int?
{
    if (month < 1 || month > 12) { return nil }

    let dateString = String(format: "%4d/%d/01", year, month)
    let dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = "yyyy/MM/dd"
    if let date = dateFormatter.dateFromString(dateString),
       let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)
    {
        calendar.firstWeekday = 2 // Monday
        let weekRange = calendar.rangeOfUnit(.WeekOfMonth, inUnit: .Month, forDate: date)
        let weeksCount = weekRange.length
        return weeksCount
    }
    else
    {
        return nil
    }
}

更新:

抱歉,我的问题不清楚。我正在尝试计算一个月中有多少周,其中包括星期一。对于 8 月,这应该是 5。

【问题讨论】:

  • 2015 年 8 月有六个不同的周,所以结果是正确的,不是吗?
  • 是的。我的意思是,不。嗯……也许。对不起...你的问题是什么?
  • 抱歉,我已经用我的真实问题更新了这个问题。

标签: swift swift2


【解决方案1】:

您的代码计算发生的周数(全部或部分) 在一个月。您显然想要的是星期一的数量 在给定的月份。使用NSDateComponents,尤其是使用 weekdayOrdinal 属性,您可以计算第一个 (weekdayOrdinal=1) 和最后一个 (weekdayOrdinal=-1) 星期一 在一个月。然后计算以周为单位的差异(并加一)。

Swift 2 中的可能实现:

func numberOfMondaysInMonth(month: Int, forYear year: Int) -> Int?
{
    let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
    calendar.firstWeekday = 2 // 2 == Monday

    // First monday in month:
    let comps = NSDateComponents()
    comps.month = month
    comps.year = year
    comps.weekday = calendar.firstWeekday
    comps.weekdayOrdinal = 1
    guard let first = calendar.dateFromComponents(comps)  else {
        return nil
    }

    // Last monday in month:
    comps.weekdayOrdinal = -1
    guard let last = calendar.dateFromComponents(comps)  else {
        return nil
    }

    // Difference in weeks:
    let weeks = calendar.components(.WeekOfMonth, fromDate: first, toDate: last, options: [])
    return weeks.weekOfMonth + 1
}

注意: 从文档中看不到负数 weekdayOrdinal 从月底倒数。观察到 Determine NSDate for Memorial Day in a given year 和 confirmed by Dave DeLong)。


Swift 3 更新:

func numberOfMondaysInMonth(_ month: Int, forYear year: Int) -> Int? {
    var calendar = Calendar(identifier: .gregorian)
    calendar.firstWeekday = 2 // 2 == Monday

    // First monday in month:
    var comps = DateComponents(year: year, month: month,
                               weekday: calendar.firstWeekday, weekdayOrdinal: 1)
    guard let first = calendar.date(from: comps)  else {
        return nil
    }

    // Last monday in month:
    comps.weekdayOrdinal = -1
    guard let last = calendar.date(from: comps)  else {
        return nil
    }

    // Difference in weeks:
    let weeks = calendar.dateComponents([.weekOfMonth], from: first, to: last)
    return weeks.weekOfMonth! + 1
}

【讨论】:

  • 以上代码:weeksInMonth(12,forYear: 2015) == 4,然而,2015 年 12 月有 5 周。
  • @MikeChirico:确切的问题是 “我正在计算一个月中有多少周,其中包括星期一。对于 8 月,这应该是 5。” – 2015 年 12 月有 4 个星期一,所以这是此处要求的结果。
  • 是的。 “鉴于,一个月中有多少个星期包括星期一”,这是一个更好的答案。这个例子很有启发性。
  • @MikeChirico:这个问题最初并不清楚,后来在更新中得到澄清。我已重命名该功能以避免误解。感谢您的反馈!
【解决方案2】:

实际上您的问题是:给定月份有多少个星期一?

我的方法是计算当月的第一个星期一,这可以通过将 CalendarUnit WeekdayOrdinal 设置为 1 来完成。然后得到总天数并做一些数学运算。

斯威夫特 1.2

func mondaysInMonth(month: Int, forYear year: Int) -> Int?
{
  if 1...12 ~= month {

    let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
    let components = NSDateComponents()
    components.weekday = 2 // Monday
    components.weekdayOrdinal = 1
    components.month = month
    components.year = year

    if let date = calendar.dateFromComponents(components)  {
      let firstDay = calendar.component(.CalendarUnitDay, fromDate: date)
      let days = calendar.rangeOfUnit(.CalendarUnitDay, inUnit:.CalendarUnitMonth, forDate:date).length
      return (days - firstDay) / 7 + 1
    }
  }
  return nil
}

斯威夫特 2

func mondaysInMonth(month: Int, forYear year: Int) -> Int?
{
  guard 1...12 ~= month else { return nil }

  let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
  let components = NSDateComponents()
  components.weekday = 2 // Monday
  components.weekdayOrdinal = 1
  components.month = month
  components.year = year

  if let date = calendar.dateFromComponents(components)  {
    let firstDay = calendar.component(.Day, fromDate: date)
    let days = calendar.rangeOfUnit(.Day, inUnit:.Month, forDate:date).length
    return (days - firstDay) / 7 + 1
  }
  return nil
}

【讨论】:

  • 4 小时没有,然后在 10 秒内 2 个答案 :)
  • :-) 我喜欢你计算每月最后一个工作日的方式。
【解决方案3】:

斯威夫特 2

以下代码计算一个月的周数。它不取决于月份的开始或结束日期。

func weeksInMonth(month: Int, year: Int) -> (Int)? {

  let calendar = NSCalendar.currentCalendar()

  let comps = NSDateComponents()
  comps.month = month+1
  comps.year = year
  comps.day = 0

  guard let last = calendar.dateFromComponents(comps) else {
    return nil
  }
  // Note: Could get other options as well
  let tag = calendar.components([.WeekOfMonth,.WeekOfYear,
       .YearForWeekOfYear,.Weekday,.Quarter],fromDate: last)

  return tag.weekOfMonth

}

// Example Usage:

if let numWeeks = weeksInMonth(8,year: 2015) {
  print(numWeeks) // Prints 6
}

if let numWeeks = weeksInMonth(12,year: 2015) {
  print(numWeeks) // Prints 5
}

【讨论】:

    【解决方案4】:

    斯威夫特 4+:

    //-- Get number of weeks from calendar
    func numberOfWeeksInMonth(_ date: Date) -> Int {
         var calendar = Calendar(identifier: .gregorian)
         calendar.firstWeekday = 1
         let weekRange = calendar.range(of: .weekOfMonth,
                                        in: .month,
                                        for: date)
         return weekRange!.count
    }
    
    //-- Implementation
    let weekCount = numberOfWeeksInMonth(Date)
    

    【讨论】:

      【解决方案5】:

      斯威夫特 4+:

      从您的组件生成日期:

      let dateComponents = DateComponents.init(year: 2019, month: 5)
      let monthCurrentDayFirst = Calendar.current.date(from: dateComponents)!
      let monthNextDayFirst = Calendar.current.date(byAdding: .month, value: 1, to: monthCurrentDayFirst)!
      let monthCurrentDayLast = Calendar.current.date(byAdding: .day, value: -1, to: monthNextDayFirst)!
      

      检测日期的周数:

      let numberOfWeeks = Calendar.current.component(.weekOfMonth, from: monthCurrentDayLast)
      

      【讨论】:

        猜你喜欢
        • 2012-07-12
        • 1970-01-01
        • 1970-01-01
        • 2022-01-10
        • 2011-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多