Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I find the beginning of the week from an NSDate?

I'm implementing a calendar view, and I'd like it to start at the beginning of the week containing a particular date. Eg. If the target date is Monday, Feb 29, 2016, and the current calendar is set to start on Sunday, I'd like my view to start with Sunday, February 28.

This seems like it should be straightforward:

let calendar = NSCalendar.currentCalendar() let firstDate = calendar.nextDateAfterDate(targetDate,                      matchingUnit: .Weekday,                            value: calendar.firstWeekday,                          options: .SearchBackwards) 

But this fails with:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Exactly one option from the set {NSCalendarMatchPreviousTimePreservingSmallerUnits, NSCalendarMatchNextTimePreservingSmallerUnits, NSCalendarMatchNextTime} must be specified.'

I can get basically what I want with:

let firstDate = calendar.nextDateAfterDate(firstDate,                      matchingUnit: .Weekday,                            value: calendar.firstWeekday,                         options: .MatchPreviousTimePreservingSmallerUnits)?                     .dateByAddingTimeInterval(-7 * 84600) 

But it seems like a bad practice, since sometimes the number of seconds in a day isn't 86400.

Is there a better way?

like image 782
Aneel Avatar asked Feb 28 '16 19:02

Aneel


1 Answers

you can use Calendar method date(from: DateComponents) passing [.yearForWeekOfYear, .weekOfYear] components from any date it will return the first day of the week from the calendar used. So if you would like to get Sunday just use Gregorian calendar. If you would like to get the Monday as the first day of the week you can use Calendar .iso8601 as you can see in this answer

Xcode 12 • Swift 5.3 or later (works with previous Swift versions as well)

extension Calendar {     static let gregorian = Calendar(identifier: .gregorian) } 

extension Date {     func startOfWeek(using calendar: Calendar = .gregorian) -> Date {         calendar.dateComponents([.calendar, .yearForWeekOfYear, .weekOfYear], from: self).date!     } } 

usage:

Date().startOfWeek()  // "Sep 20, 2020 at 12:00 AM" 


If you would like to get the beginning of week at a particular timezone you just need to use a custom calendar:

var gregorianUTC = Calendar.gregorian gregorianUTC.timeZone = TimeZone(identifier: "UTC")! print(Date().startOfWeek(using: gregorianUTC))  // "2020-09-20 00:00:00 +0000\n" 
like image 149
Leo Dabus Avatar answered Sep 20 '22 17:09

Leo Dabus