Bogdan Bogdanov
Bogdan Bogdanov

Reputation: 992

Swift - Start day and end day of the week before previous week

Today is Friday 6 March. How to find that 16 Feb is the start day and 22 Feb is the end day of the week before previous week. 16 is for my country Bulgaria in USA will be 15 and 21 I use .currentCalendar()

Upvotes: 3

Views: 8909

Answers (4)

staticVoidMan
staticVoidMan

Reputation: 20234

Swift 4+:

A very straightforward approach using mainly Calendar with the help of DateComponents:

  1. Get Date
  2. Go to previous week
    • Calendar.current.date(byAdding: .weekdayOrdinal, value: -1, to: aDate)
  3. Get the current weekday
    • Calendar.current.component(.weekday, from: bDate)
  4. Compute an offset from this weekday
    • Negative offset to reach the start of week
    • Positive offset to the reach end of the week
  5. Use offset to go to the required date
    • Calendar.current.date(byAdding: .day, value: offset, to: bDate)

Solution:

extension Date {
    var firstWeekdayOfLastWeek: Date? {
        guard let previousWeek = Calendar.current.date(byAdding: .weekdayOrdinal,
                                                       value: -1, to: self)
        else { return nil }
        
        let offsetToFirstWeekday: Int = {
            let currentWeekday = Calendar.current.component(.weekday, from: previousWeek)
            guard currentWeekday > 0 else { return 0 }
            return 1 - currentWeekday
        }()
        
        let result = Calendar.current.date(byAdding: .day,
                                           value: offsetToFirstWeekday,
                                           to: previousWeek)
        return result
    }
    
    var lastWeekdayOfLastWeek: Date? {
        guard let previousWeek = Calendar.current.date(byAdding: .weekdayOrdinal,
                                                       value: -1, to: self)
        else { return nil }
        
        let offsetToLastWeekday: Int = {
            let currentWeekday = Calendar.current.component(.weekday, from: previousWeek)
            return 7 - currentWeekday
        }()
        
        let result = Calendar.current.date(byAdding: .day,
                                           value: offsetToLastWeekday,
                                           to: previousWeek)
        return result
    }
}

Usage Example:

let formatter = DateFormatter()
formatter.dateStyle = .long

let date = Date()

//My current system date (as of time of writing)
print(formatter.string(from: currentDate))                  //December 11, 2020

//Results (my system has Sunday as the start of the week)
print(formatter.string(from: date.firstWeekdayOfLastWeek!)) //November 29, 2020
print(formatter.string(from: date.lastWeekdayOfLastWeek!))  //December 5, 2020

Force unwrap is for example purposes only

Upvotes: 0

Rob C
Rob C

Reputation: 366

If anyone looking for swift 3 answer:

func startOfWeek(weekday: Int?) -> Date {
    var cal = Calendar.current
    var component = cal.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self)
    component.to12am()
    cal.firstWeekday = weekday ?? 1
    return cal.date(from: component)!
}

func endOfWeek(weekday: Int) -> Date {
    let cal = Calendar.current
    var component = DateComponents()
    component.weekOfYear = 1
    component.day = -1
    component.to12pm()
    return cal.date(byAdding: component, to: startOfWeek(weekday: weekday))!
}

I set to 00:00:00 of that day

 internal extension DateComponents {
    mutating func to12am() {
        self.hour = 0
        self.minute = 0
        self.second = 0
    }

    mutating func to12pm(){
        self.hour = 23
        self.minute = 59
        self.second = 59
    }
}

Upvotes: 4

brandonscript
brandonscript

Reputation: 72865

A simpler Swift 2 alternative as an extension, derived from Martin R's answer for getting the end of the month:

extension: NSDate {
    func startOfWeek(weekday: Int?) -> NSDate? {
        guard
            let cal: NSCalendar = NSCalendar.currentCalendar(),
            let comp: NSDateComponents = cal.components([.YearForWeekOfYear, .WeekOfYear], fromDate: self) else { return nil }
        comp.to12pm()
        cal.firstWeekday = weekday ?? 1
        return cal.dateFromComponents(comp)!
    }

    func endOfWeek(weekday: Int) -> NSDate? {
        guard
            let cal: NSCalendar = NSCalendar.currentCalendar(),
            let comp: NSDateComponents = cal.components([.WeekOfYear], fromDate: self) else { return nil }
        comp.weekOfYear = 1
        comp.day -= 1
        comp.to12pm()
        return cal.dateByAddingComponents(comp, toDate: self.startOfWeek(weekday)!, options: [])!
    }
}

Usage:

// Use 2 for Monday, 1 for Sunday:
print(NSDate().startOfWeek(1)!) // "2016-01-24 08:00:00 +0000\n"
print(NSDate().endOfWeek(1)!) // "2016-01-30 08:00:00 +0000\n"

To guard against DST and such, you should also implement an extension to force the time to 12 pm:

internal extension NSDateComponents {
    func to12pm() {
        self.hour = 12
        self.minute = 0
        self.second = 0
    }
}

Upvotes: 4

sbooth
sbooth

Reputation: 16976

Something like this should work:

let cal = NSCalendar.currentCalendar()

let components = NSDateComponents()
components.weekOfYear -= 1

if let date = cal.dateByAddingComponents(components, toDate: NSDate(), options: NSCalendarOptions(0)) {
    var beginningOfWeek: NSDate?
    var weekDuration = NSTimeInterval()
    if cal.rangeOfUnit(.CalendarUnitWeekOfYear, startDate: &beginningOfWeek, interval: &weekDuration, forDate: date) {
        let endOfWeek = beginningOfWeek?.dateByAddingTimeInterval(weekDuration)
        print(beginningOfWeek) // Optional(2015-02-15 05:00:00 +0000)
        print(endOfWeek) // Optional(2015-02-22 05:00:00 +0000)
    }
}

Upvotes: 10

Related Questions