# 用DateComponents 实现奇葩的日历

• 周日在第一列
• 周一在第一列

no, no, no, too simple, so naive

## 需求

• 列出从今天所在周之后三周的日期（好拗口，看下面的效果图）
• 周一在第一列

``// v1.0 // 获取今天的 DateComponents let todayComponents = Calendar.current.dateComponents(in: TimeZone.current, from: Date())  // 新建 firstDateComponents, year, weekOfYeear与todayComponents一致， weekday 初始化为周一(值为2) var firstDateComponents = DateComponents.init() firstDateComponents.year = todayComponents.year firstDateComponents.weekOfYear = todayComponents.weekOfYear firstDateComponents.yearForWeekOfYear = todayComponents.yearForWeekOfYear firstDateComponents.weekday = 2  // 转换为日期 var firstDate = Calendar.current.date(from: firstDateComponents)``

#### DateComponents

`DateComponents``struct`类型，带有`year` `month` `day` `weekday` `weekOfYear`等日历相关的信息

• `weekday` 代表周一、周二这样的信息，枚举值对应的是
• 周日 = 1
• 周一 = 2
• 周六 = 7
• `weekOfYear` 代表一年中的第几周

#### 分析

• `firstDayOfWeek` 为周一时， `todayWeekday` 为周日，需要回滚一周
• `firstDayOfWeek` 为周二时， `todayWeekday` 为周日、周一，需要回滚一周
• `firstDayOfWeek` 为周三时， `todayWeekday` 为周日、周一、周二，需要回滚一周
• 以此类推，得出结论当 `firstDayOfWeek > todayWeekday` 时，需要回滚一周

## 代码

``enum Weekday: Int {     case sunday = 1, monday, tuesday, wednesday, thursday, friday, saturday      func string() -> String {         var title = ""          switch self {         case .sunday:             title = "周日"         case .monday:             title = "周一"         case .tuesday:             title = "周二"         case .wednesday:             title = "周三"         case .thursday:             title = "周四"         case .friday:             title = "周五"         case .saturday:             title = "周六"         }          return title     } }  extension Date {     /// 获取从本周开始的日期数组     ///     /// - parameter weeks:          共获取几周的数据，必须大于0     /// - parameter firstDayOfWeek: 周的第一天是周一还是周日     ///     /// - returns: 日期数组     static func datesFromThisWeek(weeks: Int, firstDayOfWeek: Weekday) -> [Date] {         var dates = [Date]()          guard weeks > 0 else {             return dates         }          let firstDate = firstDateOfThisWeek(firstDayOfWeek: firstDayOfWeek)         dates.append(firstDate)          for index in 1...(weeks * 7 - 1) {             dates.append(firstDate.add(day: index))         }          return dates     }      /// 获取当周的第一天     ///     /// - parameter firstDayOfWeek: 日历的第一列是周几     ///     /// - returns: 第一天     static func firstDateOfThisWeek(firstDayOfWeek: Weekday) -> Date {         let todayComponents = Calendar.current.dateComponents(in: TimeZone.current, from: Date())          var firstDateComponents = DateComponents.init()         firstDateComponents.year = todayComponents.year         firstDateComponents.weekOfYear = todayComponents.weekOfYear         firstDateComponents.yearForWeekOfYear = todayComponents.yearForWeekOfYear         firstDateComponents.weekday = firstDayOfWeek.rawValue          var firstDate = Calendar.current.date(from: firstDateComponents)         if firstDayOfWeek.rawValue > todayComponents.weekday! {             // 如果第一列与今天不在同一周，需要特殊处理，取上周的数据             firstDate = firstDate?.add(day: -7)         }         return firstDate!     }      /// 获取当周的最后一天     ///     /// - parameter firstDayOfWeek: 日历的第一列是周几     ///     /// - returns: 最后一天     static func lastDateOfThisWeek(firstDayOfWeek: Weekday) -> Date {         let firstDate = firstDateOfThisWeek(firstDayOfWeek: firstDayOfWeek)         return firstDate.add(day: 6)     }      /// 获得新的日期     ///     /// - parameter day: 可以为正数和负数，正数为未来的日期，负数为过去的日期     ///     /// - returns: 新的日期     func add(day: Int) -> Date {         var addingDayComponents = DateComponents.init()         addingDayComponents.day = day         return Calendar.current.date(byAdding: addingDayComponents, to: self)!     } }``