swiftdatenscalendar

How to get Monday's date of the current week in swift


I'm trying to get Monday's date of the current week. This is treated as the first day of the week in my table view. I also need to get Sunday's of the current week. This is treated as the last day of the week in my table view.

Current attempt:

let date = NSDate()
let calendar = NSCalendar.currentCalendar()
calendar.firstWeekday = 1
//attempt to changefirstday

let dateFormatter = NSDateFormatter()
let theDateFormat = NSDateFormatterStyle.ShortStyle
let theTimeFormat = NSDateFormatterStyle.ShortStyle
dateFormatter.dateStyle = theDateFormat
dateFormatter.timeStyle = theTimeFormat

let currentDateComponents = calendar.components([.YearForWeekOfYear, .WeekOfYear ], fromDate: date)
let startOfWeek = calendar.dateFromComponents(currentDateComponents)
print("startOfWeek is \(startOfWeek)")
let stringDate = dateFormatter.stringFromDate(startOfWeek!)
print("string date is \(stringDate)") //This is returning Sunday's date

Solution

  • I wrote Date extensions to get Date for certain weekday and here is how easy it is to use with Swift 5,

    Date.today()                                  // Oct 15, 2019 at 9:21 AM
    Date.today().next(.monday)                    // Oct 21, 2019 at 9:21 AM
    Date.today().next(.sunday)                    //  Oct 20, 2019 at 9:21 AM
    
    
    Date.today().previous(.sunday)                // Oct 13, 2019 at 9:21 AM
    Date.today().previous(.monday)                // Oct 14, 2019 at 9:21 AM
    
    Date.today().previous(.thursday)              // Oct 10, 2019 at 9:21 AM
    Date.today().next(.thursday)                  // Oct 17, 2019 at 9:21 AM
    Date.today().previous(.thursday,
                          considerToday: true)    // Oct 10, 2019 at 9:21 AM
    
    
    Date.today().next(.monday)
                .next(.sunday)
                .next(.thursday)                  // Oct 31, 2019 at 9:21 AM
    

    And here is Date extension for that,

    extension Date {
    
      static func today() -> Date {
          return Date()
      }
    
      func next(_ weekday: Weekday, considerToday: Bool = false) -> Date {
        return get(.next,
                   weekday,
                   considerToday: considerToday)
      }
    
      func previous(_ weekday: Weekday, considerToday: Bool = false) -> Date {
        return get(.previous,
                   weekday,
                   considerToday: considerToday)
      }
    
      func get(_ direction: SearchDirection,
               _ weekDay: Weekday,
               considerToday consider: Bool = false) -> Date {
    
        let dayName = weekDay.rawValue
    
        let weekdaysName = getWeekDaysInEnglish().map { $0.lowercased() }
    
        assert(weekdaysName.contains(dayName), "weekday symbol should be in form \(weekdaysName)")
    
        let searchWeekdayIndex = weekdaysName.firstIndex(of: dayName)! + 1
    
        let calendar = Calendar(identifier: .gregorian)
    
        if consider && calendar.component(.weekday, from: self) == searchWeekdayIndex {
          return self
        }
    
        var nextDateComponent = calendar.dateComponents([.hour, .minute, .second], from: self)
        nextDateComponent.weekday = searchWeekdayIndex
    
        let date = calendar.nextDate(after: self,
                                     matching: nextDateComponent,
                                     matchingPolicy: .nextTime,
                                     direction: direction.calendarSearchDirection)
    
        return date!
      }
    
    }
    
    // MARK: Helper methods
    extension Date {
      func getWeekDaysInEnglish() -> [String] {
        var calendar = Calendar(identifier: .gregorian)
        calendar.locale = Locale(identifier: "en_US_POSIX")
        return calendar.weekdaySymbols
      }
    
      enum Weekday: String {
        case monday, tuesday, wednesday, thursday, friday, saturday, sunday
      }
    
      enum SearchDirection {
        case next
        case previous
    
        var calendarSearchDirection: Calendar.SearchDirection {
          switch self {
          case .next:
            return .forward
          case .previous:
            return .backward
          }
        }
      }
    }