How to get dates for every thursday or other day of week in specific month? - ios

I want to get date of particular day for every week.
Suppose I have a date: 2017-04-13. It is an April, and 13 April is Thursday. I need to get every date in April which is Thursday.
How can I do this?
The output should be: 2017-04-06, 2017-04-13, 2017-04-20, 2017-04-27

Short solution:
// Get current calendar and current date
let calendar = Calendar.current
let now = Date()
// Get the current date components for year, month, weekday and weekday ordinal
var components = calendar.dateComponents([.year, .month, .weekdayOrdinal, .weekday], from: now)
// get the range (number of occurrences) of the particular weekday in the month
let range = calendar.range(of: .weekdayOrdinal, in: .month, for: now)!
// Loop thru the range, set the components to the appropriate weekday ordinal and get the date
for ordinal in range.lowerBound..
Be aware that print prints dates always in UTC.
Edit:
range(of: .weekdayOrdinal, in: .month does not work, it returns 1..<6 regardless of the date.
This is a working alternative. It checks if the date exceeds the month bounds
// Get current calendar and date for 2017/4/13
let calendar = Calendar.current
let april13Components = DateComponents(year:2017, month:4, day:13)
let april13Date = calendar.date(from: april13Components)!
// Get the current date components for year, month, weekday and weekday ordinal
var components = calendar.dateComponents([.year, .month, .weekdayOrdinal, .weekday], from: april13Date)
// Loop thru the range, set the components to the appropriate weekday ordinal and get the date
for ordinal in 1..<6 { // maximum 5 occurrences
components.weekdayOrdinal = ordinal
let date = calendar.date(from: components)!
if calendar.component(.month, from: date) != components.month! { break }
print(calendar.date(from: components)!)
}

Try this playground:
import UIKit
let dateString = "2017-04-13"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let referenceDate = dateFormatter.date(from: dateString)!
let calendar = Calendar.current
let firstDayComponents = calendar.dateComponents([.year, .month], from: referenceDate)
let monthFirst = calendar.date(from: firstDayComponents)!
let weekDay = calendar.component(.weekday, from: referenceDate)
var oneDay = DateComponents()
oneDay.day = 1
var checkDate = monthFirst
while calendar.component(.month, from: checkDate) == calendar.component(.month, from: referenceDate) {
if calendar.component(.weekday, from: checkDate) == weekDay {
let thisDay = dateFormatter.string(from: checkDate)
print(thisDay)
}
checkDate = calendar.date(byAdding: oneDay, to: checkDate)!
}

This code does the job. I added some logs to understand some logic behind it.
You can set dateInit as you wish, the rest of the code will find all the days that have the same weekday in the same year of the same month.
I printed two versions of date representations (NSDate objects and NSString objects), for the one having issue with timezones and "it's not the same day" cries.
It uses enumerateDatesStartingAfterDate:matchingComponents:options:usingBlock:
NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
NSString *dateStr = #"2017-04-13";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSDate *dateInit = [dateFormatter dateFromString:dateStr];
NSLog(#"dateInit: %#", dateInit);
NSDateComponents *componentsToMatch = [calendar components:(NSCalendarUnitMonth|NSCalendarUnitWeekday) fromDate:dateInit];
NSDate *startOfMonth = [calendar dateFromComponents:[calendar components:(NSCalendarUnitYear|NSCalendarUnitMonth) fromDate:dateInit]];
NSLog(#"StartOfTheMonth: %#", startOfMonth);
NSArray *daysToFind = #[#"2017-04-06", #"2017-04-13", #"2017-04-20", #"2017-04-27"]; //According to author
NSLog(#"DaysToFind: %#", daysToFind);
NSMutableArray *allDaysInMonthMatchingWeekDay = [[NSMutableArray alloc] init];
[calendar enumerateDatesStartingAfterDate:startOfMonth
matchingComponents:componentsToMatch
options:NSCalendarMatchStrictly
usingBlock:^(NSDate * _Nullable date, BOOL exactMatch, BOOL * _Nonnull stop) {
NSLog(#"DateBlock: %#", date);
[allDaysInMonthMatchingWeekDay addObject:date];
}];
NSLog(#"allDaysInMonthMatchingWeekDay: %#",allDaysInMonthMatchingWeekDay);
for (NSDate *aDate in allDaysInMonthMatchingWeekDay)
{
NSLog(#"Found: %#", [dateFormatter stringFromDate:aDate]);
}
The logs:
$>dateInit: 2017-04-12 22:00:00 +0000
$>StartOfTheMonth: 2017-03-31 22:00:00 +0000
$>DaysToFind: (
"2017-04-06",
"2017-04-13",
"2017-04-20",
"2017-04-27"
)
$>DateBlock: 2017-04-05 22:00:00 +0000
$>DateBlock: 2017-04-12 22:00:00 +0000
$>DateBlock: 2017-04-19 22:00:00 +0000
$>DateBlock: 2017-04-26 22:00:00 +0000
$>allDaysInMonthMatchingWeekDay: (
"2017-04-05 22:00:00 +0000",
"2017-04-12 22:00:00 +0000",
"2017-04-19 22:00:00 +0000",
"2017-04-26 22:00:00 +0000"
)
$>Found: 2017-04-06
$>Found: 2017-04-13
$>Found: 2017-04-20
$>Found: 2017-04-27
Note: For the componentsToMatch, I tried to set the Year/Month/WeekDay flags unit, but the enumeration stopped at the first occurence, didn't search long why, I came up with only month and weekday flag to get it work. Maybe some little issue that I missed.
EDIT:
In Swift 3 (it works, but since I'm an Objective-C developer and not a Swift one, it may have issues, like wrapping/unwrapping etc)
let calendar = NSCalendar.init(calendarIdentifier: .gregorian)
let dateStr = "2017-04-13"
let dateFormatter = DateFormatter.init()
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateInit = dateFormatter.date(from: dateStr)!
print("dateInit: \(dateInit)")
let componentsToMatch = calendar?.components([.month,.weekday], from: dateInit)
let startOfMonth = calendar?.date(from: (calendar?.components([.year,.month], from: dateInit))!)
print("StartOfTheMonth:\(startOfMonth)")
calendar?.enumerateDates(startingAfter: startOfMonth!, matching: componentsToMatch!, options: .matchStrictly, using: { (date, extactMatch, stop) in
print("DateBlock: \(date)")
})

I would write an extension for Calendar for any given time span and use an enum to name the weekdays
enum WeekDay: Int {
case sunday = 1
case monday
case tuesday
case wednesday
case thursday
case friday
case saturday
}
struct TimeSpan {
let startDate: Date
let endDate: Date
}
extension Calendar {
func allOccurrenceOf(day: WeekDay, in timeSpan:TimeSpan) -> [Date] {
let startDateWeekDay = Int(self.component(.weekday, from: timeSpan.startDate))
let desiredDay = day.rawValue
let offset = (desiredDay - startDateWeekDay + 7) % 7
let firstOccurrence = self.startOfDay(for:self.date(byAdding: DateComponents(day:offset), to: timeSpan.startDate)!)
guard firstOccurrence.timeIntervalSince1970 < timeSpan.endDate.timeIntervalSince1970 else {
return []
}
var filtered = [firstOccurrence]
while true {
let nextDate = self.date(byAdding: DateComponents(day: 7), to: filtered.last!)!
if nextDate < timeSpan.endDate {
filtered.append(nextDate)
break
}
}
return filtered
}
}
Beware that I hacked this could rather fast. I am sure that this can be expressed swiftier. In real production code I would also try to eliminate all ! from it.
usage:
let tuesdays = Calendar.autoupdatingCurrent.allOccurrenceOf(day: .tuesday, in: TimeSpan(startDate: Date(), endDate: Calendar.autoupdatingCurrent.date(byAdding: DateComponents(month:1), to: Date())!))

As Suggested in comment. see updated code. updated with week day
func getNumberOfDaysInMonth (month : Int , Year : Int, weekday: Int) -> [String]{
let dateComponents = NSDateComponents()
dateComponents.year = Year
dateComponents.month = month
let calendar = Calendar.current
let date = calendar.date(from: dateComponents as DateComponents)
let range = calendar.range(of: .day, in: .month, for: date!)
let numDays:Int = (range?.upperBound)!
let thuFormatter = DateFormatter()
var dateArray:[String] = [String]()
thuFormatter.dateFormat = "yyyy-MM-dd"
for day in 1...numDays {
dateComponents.day = day
let date2 = calendar.date(from: dateComponents as DateComponents)
print(calendar.component(.weekday, from: date2!))
if calendar.component(.weekday, from: date2!) == weekday
{
let dateThu = thuFormatter.string(from: date2!)
dateArray.append(dateThu)
}
}
return dateArray
}
and then call it like
let myThu:[String] = getNumberOfDaysInMonth(month: 4, Year: 2017,weekday: 3)
print(myThu)

Related

How would you set a date to a specific value in swift? [duplicate]

I have an NSDate object and I want to set it to an arbitrary time (say, midnight) so that I can use the timeIntervalSince1970 function to retrieve data consistently without worrying about the time when the object is created.
I've tried using an NSCalendar and modifying its components by using some Objective-C methods, like this:
let date: NSDate = NSDate()
let cal: NSCalendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)!
let components: NSDateComponents = cal.components(NSCalendarUnit./* a unit of time */CalendarUnit, fromDate: date)
let newDate: NSDate = cal.dateFromComponents(components)
The problem with the above method is that you can only set one unit of time (/* a unit of time */), so you could only have one of the following be accurate:
Day
Month
Year
Hours
Minutes
Seconds
Is there a way to set hours, minutes, and seconds at the same time and retain the date (day/month/year)?
Your statement
The problem with the above method is that you can only set one unit of
time ...
is not correct. NSCalendarUnit conforms to the RawOptionSetType protocol which
inherits from BitwiseOperationsType. This means that the options can be bitwise
combined with & and |.
In Swift 2 (Xcode 7) this was changed again to be
an OptionSetType which offers a set-like interface, see
for example Error combining NSCalendarUnit with OR (pipe) in Swift 2.0.
Therefore the following compiles and works in iOS 7 and iOS 8:
let date = NSDate()
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
// Swift 1.2:
let components = cal.components(.CalendarUnitDay | .CalendarUnitMonth | .CalendarUnitYear, fromDate: date)
// Swift 2:
let components = cal.components([.Day , .Month, .Year ], fromDate: date)
let newDate = cal.dateFromComponents(components)
(Note that I have omitted the type annotations for the variables, the Swift compiler
infers the type automatically from the expression on the right hand side of
the assignments.)
Determining the start of the given day (midnight) can also done
with the rangeOfUnit() method (iOS 7 and iOS 8):
let date = NSDate()
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
var newDate : NSDate?
// Swift 1.2:
cal.rangeOfUnit(.CalendarUnitDay, startDate: &newDate, interval: nil, forDate: date)
// Swift 2:
cal.rangeOfUnit(.Day, startDate: &newDate, interval: nil, forDate: date)
If your deployment target is iOS 8 then it is even simpler:
let date = NSDate()
let cal = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
let newDate = cal.startOfDayForDate(date)
Update for Swift 3 (Xcode 8):
let date = Date()
let cal = Calendar(identifier: .gregorian)
let newDate = cal.startOfDay(for: date)
Yes.
You don't need to fiddle with the components of the NSCalendar at all; you can simply call the dateBySettingHour method and use the ofDate parameter with your existing date.
let date: NSDate = NSDate()
let cal: NSCalendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)!
let newDate: NSDate = cal.dateBySettingHour(0, minute: 0, second: 0, ofDate: date, options: NSCalendarOptions())!
For Swift 3:
let date: Date = Date()
let cal: Calendar = Calendar(identifier: .gregorian)
let newDate: Date = cal.date(bySettingHour: 0, minute: 0, second: 0, of: date)!
Then, to get your time since 1970, you can just do
let time: NSTimeInterval = newDate.timeIntervalSince1970
dateBySettingHour was introduced in OS X Mavericks (10.9) and gained iOS support with iOS 8.
Declaration in NSCalendar.h:
/*
This API returns a new NSDate object representing the date calculated by setting hour, minute, and second to a given time.
If no such time exists, the next available time is returned (which could, for example, be in a different day than the nominal target date).
The intent is to return a date on the same day as the original date argument. This may result in a date which is earlier than the given date, of course.
*/
- (NSDate *)dateBySettingHour:(NSInteger)h minute:(NSInteger)m second:(NSInteger)s ofDate:(NSDate *)date options:(NSCalendarOptions)opts NS_AVAILABLE(10_9, 8_0);
Here's an example of how you would do it, without using the dateBySettingHour function (to make sure your code is still compatible with iOS 7 devices):
NSDate* now = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:now];
NSDate* midnightLastNight = [gregorian dateFromComponents:dateComponents];
Yuck.
There is a reason why I prefer coding in C#...
Anyone fancy some readable code..?
DateTime midnightLastNight = DateTime.Today;
;-)
Swift 5+
let date = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: Date())
Swift iOS 8 and up: People tend to forget that the Calendar and DateFormatter objects have a TimeZone. If you do not set the desired timzone and the default timezone value is not ok for you, then the resulting hours and minutes could be off.
Note: In a real app you could optimize this code some more.
Note: When not caring about timezones, the results could be OK on one device, and bad on an other device just because of different timezone settings.
Note: Be sure to add an existing timezone identifier! This code does not handle a missing or misspelled timezone name.
func dateTodayZeroHour() -> Date {
var cal = Calendar.current
cal.timeZone = TimeZone(identifier: "Europe/Paris")!
return cal.startOfDay(for: Date())
}
You could even extend the language. If the default timezone is fine for you, do not set it.
extension Date {
var midnight: Date {
var cal = Calendar.current
cal.timeZone = TimeZone(identifier: "Europe/Paris")!
return cal.startOfDay(for: self)
}
var midday: Date {
var cal = Calendar.current
cal.timeZone = TimeZone(identifier: "Europe/Paris")!
return cal.date(byAdding: .hour, value: 12, to: self.midnight)!
}
}
And use it like this:
let formatter = DateFormatter()
formatter.timeZone = TimeZone(identifier: "Europe/Paris")
formatter.dateFormat = "yyyy/MM/dd HH:mm:ss"
let midnight = Date().midnight
let midnightString = formatter.string(from: midnight)
let midday = Date().midday
let middayString = formatter.string(from: midday)
let wheneverMidnight = formatter.date(from: "2018/12/05 08:08:08")!.midnight
let wheneverMidnightString = formatter.string(from: wheneverMidnight)
print("dates: \(midnightString) \(middayString) \(wheneverMidnightString)")
The string conversions and the DateFormatter are needed in our case for some formatting and to move the timezone since the date object in itself does not keep or care about a timezone value.
Watch out! The resulting value could differ because of a timezone offset somewhere in your calculating chain!
Just in case someone is looking for this:
Using SwiftDate you could just do this:
Date().atTime(hour: 0, minute: 0, second: 0)
In my opinion, the solution, which is easiest to verify, but perhaps not the quickest, is to use strings.
func set( hours: Int, minutes: Int, seconds: Int, ofDate date: Date ) -> Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let newDateString = "\(dateFormatter.string(from: date)) \(hours):\(minutes):\(seconds)"
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return dateFormatter.date(from: newDateString)
}
func resetHourMinuteSecond(date: NSDate, hour: Int, minute: Int, second: Int) -> NSDate{
let nsdate = NSCalendar.currentCalendar().dateBySettingHour(hour, minute: minute, second: second, ofDate: date, options: NSCalendarOptions(rawValue: 0))
return nsdate!
}
Use the current calendar to get the start of the day for the current time.
let today = Calendar.current.startOfDay(for: Date())

Converting the string to date giving different format [duplicate]

This question already has answers here:
Getting date from [NSDate date] off by a few hours
(3 answers)
Closed 3 years ago.
Converting from string to date and date to string time format is changing the original data.
Tried with dateComponents as well by giving the hour and minute
var calendar = Calendar.current
let components = calendar.dateComponents([.year, .month, .day, .hour], from: calFrom)
calendar.timeZone = .current
// Specify date components
var dateComponents:DateComponents = calendar.dateComponents([.year, .month, .day, .hour], from: Date())
dateComponents.year = components.year
dateComponents.month = components.month
dateComponents.day = components.day
dateComponents.hour = 08//Cutomised hour
dateComponents.minute = 34//Cutomised Minutes
// Create date from components
let someDateTime = calendar.date(from: dateComponents)
print(someDateTime!)
Actual Output:
2019-04-02 03:04:00 +0000
Expected Output:
2019-04-02 08:34:00 +0000
I tried with below code as well. Converting the date to String and manually appending the hour and minutes to the string and converting back to the date.
let calFrom = Date()
let formatter = DateFormatter()
formatter.dateFormat = "dd/MM/yyyy"
var calFromDate = formatter.string(from: calFrom)
calFromDate = calFromDate + " 09" + ":30"
print(calFromDate)
//Output 02/04/2019 09:30
formatter.dateFormat = "dd/MM/yyyy hh:mm"
formatter.locale = Locale.current// set locale to reliable US_POSIX
let date1 = formatter.date(from: calFromDate)
print(date1!)
Actual Output:
2019-04-02 04:00:00 +0000
Expected Output:
02/04/2019 09:30
How to get the exact time that has given in the output?
Date used to update the hour and minute components has UTC timezone so calendar should also have the same timeZone as below,
calendar.timeZone = TimeZone(abbreviation: "UTC")!

How to get all days in a month that are a specific weekday?

How do I get the actual date of the month based on a given a day ? For example, I would like to retrieve all the dates in June 2017 which are Saturday. How can I achieve that ? Sample code will be very much appreciated as I have struggled for days on this.
A DateComponents has a weekday property, representing the day of the week. The weekdays are (in Foundation's Gregorian calendar) numbered 1 for Sunday, 2 for Monday, …, and 7 for Saturday.
A DateComponents also has a weekdayOrdinal property, representing “the position of the weekday within the next larger calendar unit, such as the month. For example, 2 is the weekday ordinal unit for the second Friday of the month.”
So let's initialize a DateComponents for some Saturday in June 2017. It's generally a good idea to specify a time of noon if you don't care about the time, because midnight (the default time of day) can cause problems in some time zones on some days.
var components = DateComponents(era: 1, year: 2017, month: 06, hour: 12, weekday: 7)
And let's make a calendar.
var calendar = Calendar.autoupdatingCurrent
Now we can loop over all the possible weekday ordinals. For each, we'll ask the calendar to generate a date. Then we ask the calendar to convert the date back to year, month, and day components.
In the Gregorian calendar, some months have 5 Saturdays, but most have 4. So when we ask for the 5th Saturday, we'll probably get a date in the following month. When that happens, we want to suppress that date.
for i in 1 ... 5 {
components.weekdayOrdinal = i
let date = calendar.date(from: components)!
let ymd = calendar.dateComponents([.year, .month, .day], from: date)
guard ymd.month == components.month else { break }
print("\(ymd.year!)-\(ymd.month!)-\(ymd.day!)")
}
Output:
2017-6-3
2017-6-10
2017-6-17
2017-6-24
Objective-C version:
NSDateComponents *components = [NSDateComponents new];
components.era = 1;
components.year = 2017;
components.month = 6;
components.hour = 12;
components.weekday = 7;
NSCalendar *calendar = NSCalendar.autoupdatingCurrentCalendar;
for (NSInteger i = 1; i <= 5; ++i) {
components.weekdayOrdinal = i;
NSDate *date = [calendar dateFromComponents:components];
NSDateComponents *ymd = [calendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:date];
if (ymd.month != components.month) { break; }
NSLog(#"%ld-%ld-%ld", (long)ymd.year, (long)ymd.month, (long)ymd.day);
}
This is another solution for your problem using calendar method called enumerateDates and using a Date extension
//month in MM format, year in yyyy format and dayNumber as Int 1 for sunday, 7 for saturday
func datesWith(dayNumber:Int,month:String,year:String) -> [Date]
{
assert(dayNumber >= 1 && dayNumber <= 7, "Day number is wrong")
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let date = dateFormatter.date(from: year + "-" + month + "-" + "01")
guard date != nil else {
return []
}
var resultDates : [Date] = []
//check if firstDay of month is desired weekday
if(Calendar.current.component(.weekday, from: date!) == dayNumber)
{
resultDates.append(date!)
}
Calendar.current.enumerateDates(startingAfter: date!, matching: DateComponents(weekday: dayNumber), matchingPolicy: Calendar.MatchingPolicy.nextTimePreservingSmallerComponents) { (currentDate, result, stop) in
if(currentDate! > date!.endOfMonth())
{
stop = true
return
}
resultDates.append(currentDate!)
}
return resultDates
}
Extension
extension Date {
func startOfMonth() -> Date {
return Calendar.current.date(from: Calendar.current.dateComponents([.year, .month], from: Calendar.current.startOfDay(for: self)))!
}
func endOfMonth() -> Date {
return Calendar.current.date(byAdding: DateComponents(month: 1, day: -1), to: self.startOfMonth())!
}
}
Using it
override func viewDidLoad() {
super.viewDidLoad()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
// Do any additional setup after loading the view, typically from a nib.
let datesArray = self.datesWith(dayNumber: 5, month: "06", year: "2017")
for currDate in datesArray {
debugPrint(dateFormatter.string(from: currDate))
}
}
Output
"2017-06-01"
"2017-06-08"
"2017-06-15"
"2017-06-22"
"2017-06-29"
Hope this helps

How to get Monday 00:00 of current week? Swift 3

I'm trying to return Monday 00:00 from my date. This is my code:
func getMonday(myDate: Date) -> Date {
let cal = Calendar.current
let comps = cal.dateComponents([.weekOfYear, .yearForWeekOfYear], from: myDate)
let beginningOfWeek = cal.date(from: comps)!
return beginningOfWeek
}
My problem is that it does not return Monday 00:00 , but Saturday 22:00.
Example:
let monday1 = getMonday(myDate: date) //date is: 2016-10-04 17:00:00
print(monday1) //Prints: 2016-10-01 22:00:00 (Saturday)
My question is:
How to return Monday 00:00 from myDate?
Thank you very much.
Your code returns the first day in the given week, that may be
a Sunday or Monday (or perhaps some other day), depending on your locale.
If you want Monday considered to be the first weekday then set
cal.firstWeekday = 2
If you want the Monday of the given week, independent of what the
start of the week is, then set comps.weekday = 2:
func getMonday(myDate: Date) -> Date {
let cal = Calendar.current
var comps = cal.dateComponents([.weekOfYear, .yearForWeekOfYear], from: myDate)
comps.weekday = 2 // Monday
let mondayInWeek = cal.date(from: comps)!
return mondayInWeek
}
Note that printing a Date always uses the GMT time zone,
you'll need a date formatter to print the result according to your local time zone. Example:
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm"
let now = Date()
print(df.string(from: now)) // 2016-10-02 20:16
let monday1 = getMonday(myDate: now)
print(df.string(from: monday1)) // 2016-09-26 00:00

while selecting sunday date it select date of next week [duplicate]

I want to get the current week start and end date and I also want to use the previous
week start and end date and next week of the start and end date in current month.
Thanks in Advance.
rangeOfUnit:startDate:interval:forDate:. It gives you the start and the interval for a certain time unit. With it it is easy to find the start of the week in the used calendar and add the range-1 to get the latest second in that week.
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
NSDate *startOfTheWeek;
NSDate *endOfWeek;
NSTimeInterval interval;
[cal rangeOfUnit:NSWeekCalendarUnit
startDate:&startOfTheWeek
interval:&interval
forDate:now];
//startOfWeek holds now the first day of the week, according to locale (monday vs. sunday)
endOfWeek = [startOfTheWeek dateByAddingTimeInterval:interval-1];
// holds 23:59:59 of last day in week.
I solve the problem thanks for Support
Code :- it give the current week start and end date.
NSDate *today = [NSDate date];
NSLog(#"Today date is %#",today);
dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd"];// you can use your format.
//Week Start Date
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorian components:NSWeekdayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:today];
int dayofweek = [[[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate:today] weekday];// this will give you current day of week
[components setDay:([components day] - ((dayofweek) - 2))];// for beginning of the week.
NSDate *beginningOfWeek = [gregorian dateFromComponents:components];
NSDateFormatter *dateFormat_first = [[NSDateFormatter alloc] init];
[dateFormat_first setDateFormat:#"yyyy-MM-dd"];
dateString2Prev = [dateFormat stringFromDate:beginningOfWeek];
weekstartPrev = [[dateFormat_first dateFromString:dateString2Prev] retain];
NSLog(#"%#",weekstartPrev);
//Week End Date
NSCalendar *gregorianEnd = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *componentsEnd = [gregorianEnd components:NSWeekdayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:today];
int Enddayofweek = [[[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate:today] weekday];// this will give you current day of week
[componentsEnd setDay:([componentsEnd day]+(7-Enddayofweek)+1)];// for end day of the week
NSDate *EndOfWeek = [gregorianEnd dateFromComponents:componentsEnd];
NSDateFormatter *dateFormat_End = [[NSDateFormatter alloc] init];
[dateFormat_End setDateFormat:#"yyyy-MM-dd"];
dateEndPrev = [dateFormat stringFromDate:EndOfWeek];
weekEndPrev = [[dateFormat_End dateFromString:dateEndPrev] retain];
NSLog(#"%#",weekEndPrev);
Here is Swift 3 Version:-
extension Date {
var startOfWeek: Date? {
let gregorian = Calendar(identifier: .gregorian)
guard let sunday = gregorian.date(from: gregorian.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self)) else { return nil }
return gregorian.date(byAdding: .day, value: 1, to: sunday)
}
var endOfWeek: Date? {
let gregorian = Calendar(identifier: .gregorian)
guard let sunday = gregorian.date(from: gregorian.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self)) else { return nil }
return gregorian.date(byAdding: .day, value: 7, to: sunday)
}
}
You can get the week start date and end date like this :
let startWeek = Date().startOfWeek
let endWeek = Date().endOfWeek
print(startWeek ?? "not found start date")
print(endWeek ?? "not found end date")
A Swift version
of vikingosegundo's answer:
let calendar = NSCalendar.currentCalendar()
var startOfTheWeek: NSDate?
var endOfWeek: NSDate!
var interval = NSTimeInterval(0)
calendar.rangeOfUnit(.WeekOfMonth, startDate: &startOfTheWeek, interval: &interval, forDate: NSDate())
endOfWeek = startOfTheWeek!.dateByAddingTimeInterval(interval - 1)
Here's an elegant way for Swift 3 (Xcode 8+):
extension Date {
var startOfWeek: Date {
let date = Calendar.current.date(from: Calendar.current.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self))!
let dslTimeOffset = NSTimeZone.local.daylightSavingTimeOffset(for: date)
return date.addingTimeInterval(dslTimeOffset)
}
var endOfWeek: Date {
return Calendar.current.date(byAdding: .second, value: 604799, to: self.startOfWeek)!
}
}
And we can use this extension like this:
print(Date().startOfWeek)
print(Date().endOfWeek)
Swift 4 Solution
I have figured out according to my requirement, where I have find out dates for following.
1. Today
2. Tomorrow
3. This Week
4. This Weekend
5. Next Week
6. Next Weekend
So, I have created Date Extension to get Dates of Current Week and Next Week.
CODE
extension Date {
func getWeekDates() -> (thisWeek:[Date],nextWeek:[Date]) {
var tuple: (thisWeek:[Date],nextWeek:[Date])
var arrThisWeek: [Date] = []
for i in 0..<7 {
arrThisWeek.append(Calendar.current.date(byAdding: .day, value: i, to: startOfWeek)!)
}
var arrNextWeek: [Date] = []
for i in 1...7 {
arrNextWeek.append(Calendar.current.date(byAdding: .day, value: i, to: arrThisWeek.last!)!)
}
tuple = (thisWeek: arrThisWeek,nextWeek: arrNextWeek)
return tuple
}
var tomorrow: Date {
return Calendar.current.date(byAdding: .day, value: 1, to: noon)!
}
var noon: Date {
return Calendar.current.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
}
var startOfWeek: Date {
let gregorian = Calendar(identifier: .gregorian)
let sunday = gregorian.date(from: gregorian.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self))
return gregorian.date(byAdding: .day, value: 1, to: sunday!)!
}
func toDate(format: String) -> String {
let formatter = DateFormatter()
formatter.dateFormat = format
return formatter.string(from: self)
}
}
USAGE:
let arrWeekDates = Date().getWeekDates() // Get dates of Current and Next week.
let dateFormat = "MMM dd" // Date format
let thisMon = arrWeekDates.thisWeek.first!.toDate(format: dateFormat)
let thisSat = arrWeekDates.thisWeek[arrWeekDates.thisWeek.count - 2].toDate(format: dateFormat)
let thisSun = arrWeekDates.thisWeek[arrWeekDates.thisWeek.count - 1].toDate(format: dateFormat)
let nextMon = arrWeekDates.nextWeek.first!.toDate(format: dateFormat)
let nextSat = arrWeekDates.nextWeek[arrWeekDates.nextWeek.count - 2].toDate(format: dateFormat)
let nextSun = arrWeekDates.nextWeek[arrWeekDates.nextWeek.count - 1].toDate(format: dateFormat)
print("Today: \(Date().toDate(format: dateFormat))") // Sep 26
print("Tomorrow: \(Date().tomorrow.toDate(format: dateFormat))") // Sep 27
print("This Week: \(thisMon) - \(thisSun)") // Sep 24 - Sep 30
print("This Weekend: \(thisSat) - \(thisSun)") // Sep 29 - Sep 30
print("Next Week: \(nextMon) - \(nextSun)") // Oct 01 - Oct 07
print("Next Weekend: \(nextSat) - \(nextSun)") // Oct 06 - Oct 07
You can modify Extension according to your need.
Thanks!
Solution for Swift 5.x
Create Date extension:
func weekPeriod() -> (startDate: Date, endDate: Date) {
let calendar = Calendar(identifier: .gregorian)
guard let sundayDate = calendar.date(from: calendar.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self)) else { return (startDate: Date(), endDate: Date()) }
if calendar.isDateInToday(sundayDate) {
let startDate = calendar.date(byAdding: .day, value: -6, to: sundayDate) ?? Date()
let endDate = sundayDate
return (startDate: startDate, endDate: endDate)
}
let startDate = calendar.date(byAdding: .day, value: 1, to: sundayDate) ?? Date()
let endDate = calendar.date(byAdding: .day, value: 6, to: startDate) ?? Date()
return (startDate: startDate, endDate: endDate)
}
First find the current date...
NSDate *today = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:today];
Calcuate number of days to substract from today, in order to get the first day of the week. In this case, the first day of the week is monday. This is represented by first subtracting 0 with the weekday integer followed by adding 2 to the setDay.
Sunday = 1, Monday = 2, Tuesday = 3, Wednesday = 4, Thursday = 5, Friday = 6 and Saturday = 7. By adding more to this integers, you will go into the next week.
NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init];
[componentsToSubtract setDay: (0 - [weekdayComponents weekday]) + 2];
[componentsToSubtract setHour: 0 - [weekdayComponents hour]];
[componentsToSubtract setMinute: 0 - [weekdayComponents minute]];
[componentsToSubtract setSecond: 0 - [weekdayComponents second]];
Create date for first day in week
NSDate *beginningOfWeek = [gregorian dateByAddingComponents:componentsToSubtract toDate:today options:0];
By adding 6 to the date of the first day, we can get the last day, in our example Sunday.
NSDateComponents *componentsToAdd = [gregorian components:NSDayCalendarUnit fromDate:beginningOfWeek];
[componentsToAdd setDay:6];
NSDate *endOfWeek = [gregorian dateByAddingComponents:componentsToAdd toDate:beginningOfWeek options:0];
for next and previous ....
-(IBAction)Week_CalendarActionEvents:(id)sender{
NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDateComponents *offsetComponents = [[[NSDateComponents alloc] init] autorelease];
NSDate *nextDate;
if(sender==Week_prevBarBtn) // Previous button events
[offsetComponents setDay:-7];
else if(sender==Week_nextBarBtn) // next button events
[offsetComponents setDay:7];
nextDate = [gregorian dateByAddingComponents:offsetComponents toDate:selectedDate options:0];
selectedDate = nextDate;
[selectedDate retain];
NSDateComponents *components = [gregorian components:NSWeekCalendarUnit fromDate:selectedDate];
NSInteger week = [components week];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MMMM YYYY"];
NSString *stringFromDate = [formatter stringFromDate:selectedDate];
[formatter release];
[Week_weekBarBtn setTitle:[NSString stringWithFormat:#"%#,Week %d",stringFromDate,week]];
}
Here's some code and it also checks an edge case where the beginning of the week starts in the prior month. You can get end of week by setting setWeekday to 7 and you can get the prior week by subtracting 1 from [components week]
// Finds the date for the first day of the week
- (NSDate *)getFirstDayOfTheWeekFromDate:(NSDate *)givenDate
{
NSCalendar *calendar = [NSCalendar currentCalendar];
// Edge case where beginning of week starts in the prior month
NSDateComponents *edgeCase = [[NSDateComponents alloc] init];
[edgeCase setMonth:2];
[edgeCase setDay:1];
[edgeCase setYear:2013];
NSDate *edgeCaseDate = [calendar dateFromComponents:edgeCase];
NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:edgeCaseDate];
[components setWeekday:1]; // 1 == Sunday, 7 == Saturday
[components setWeek:[components week]];
NSLog(#"Edge case date is %# and beginning of that week is %#", edgeCaseDate , [calendar dateFromComponents:components]);
// Find Sunday for the given date
components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:givenDate];
[components setWeekday:1]; // 1 == Sunday, 7 == Saturday
[components setWeek:[components week]];
NSLog(#"Original date is %# and beginning of week is %#", givenDate , [calendar dateFromComponents:components]);
return [calendar dateFromComponents:components];
}
Here is a solution for the swift4,
we can get all the days for the current week.
var calendar = Calendar(identifier: Calendar.Identifier.gregorian)
let today = calendar.startOfDay(for: Date())
let dayOfWeek = calendar.component(.weekday, from: today) - calendar.firstWeekday
let weekdays = calendar.range(of: .weekday, in: .weekOfYear, for: today)!
let days = (weekdays.lowerBound ..< weekdays.upperBound)
.flatMap { calendar.date(byAdding: .day, value: $0 - dayOfWeek, to: today) }
//Begining of Week Date
- (NSDate*) beginingOfWeekOfDate{
NSCalendar *tmpCalendar = [NSCalendar currentCalendar];
NSDateComponents *components = [tmpCalendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitWeekOfYear|NSCalendarUnitWeekday fromDate:self];//get the required calendar units
NSInteger weekday = tmpCalendar.firstWeekday;
components.weekday = weekday; //weekday
components.hour = 0;
components.minute = 0;
components.second = 0;
NSDate *fireDate = [tmpCalendar dateFromComponents:components];
return fireDate;
}
//End of Week Date
-(NSDate *)endOfWeekFromDate{
NSCalendar *tmpCalendar = [NSCalendar currentCalendar];
NSDateComponents *components = [tmpCalendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitWeekOfYear|NSCalendarUnitWeekday fromDate:self];//get the required calendar units
int weekday = 7; //Saturday
if (tmpCalendar.firstWeekday != 1) {
weekday = 1;
}
components.weekday = weekday;//weekday
components.hour = 23;
components.minute = 59;
components.second = 59;
NSDate *fireDate = [tmpCalendar dateFromComponents:components];
return fireDate;
}
You can get current day and date by following code:
NSDate *today = [NSDate date];
NSDateFormatter *dateFormat = [[[NSDateFormatter alloc] init] autorelease];
[dateFormat setDateFormat:#"EEEE"];
NSString *weekDay = [dateFormat stringFromDate:today];
[dateFormat setDateFormat:#"dd"];
NSString *thedate=[dateFormat stringFromDate:today];
//[dateFormat release];
NSLog(#"%# %#", weekDay,thedate);
Now, You need to put some logic in it to calculate starting date and end date of the week. The logic will be such kind,
if the week day is Monday
then
starting date = current date - 0
end date = current date + 6
and so on
I think you can get the idea of it.
By take advantage of the method rangeOfUnit:startDate:interval:forDate: of NSDate, there is a simpler way to achieve this:
- (void)startDate:(NSDate **)start andEndDate:(NSDate **)end ofWeekOn:(NSDate *)date{
NSDate *startDate = nil;
NSTimeInterval duration = 0;
BOOL b = [[NSCalendar currentCalendar] rangeOfUnit:NSWeekCalendarUnit startDate:&startDate interval:&duration forDate:date];
if(! b){
*start = nil;
*end = nil;
return;
}
NSDate *endDate = [startDate dateByAddingTimeInterval:duration-1];
*start = startDate;
*end = endDate;
}
NSDate *this_start = nil, *this_end = nil;
[self startDate:&this_start andEndDate:&this_end ofWeekOn:[NSDate date]];
So now you have the start date and end date of this week. Then last week:
NSDate *lastWeekDate = [this_start dateByAddingTimeInterval:-10];
NSDate *last_start = nil, *last_end = nil;
[self startDate:&last_start andEndDate:&last_end ofWeekOn:lastWeekDate];
Next week:
NSDate *nextWeekDate = [this_end dateByAddingTimeInterval:10];
NSDate *next_start = nil, *next_end = nil;
[self startDate:&next_start andEndDate:&next_end ofWeekOn:nextWeekDate];
Now you have them all.
Swift 3
First find the current date...
let today = Date()
let gregorian = Calendar(identifier: .gregorian)
var weekdayComponents: DateComponents? = gregorian.dateComponents([.weekday], from: today)
Sunday = 1, Monday = 2, Tuesday = 3, Wednesday = 4, Thursday = 5, Friday = 6 and Saturday = 7.
var componentsToSubtract = DateComponents()
componentsToSubtract.day = (0 - (weekdayComponents?.weekday!)!) + 2
beginningOfWeek = gregorian.date(byAdding: componentsToSubtract, to: today)
var componentsToAdd: DateComponents? = gregorian.dateComponents([.day], from: beginningOfWeek!)
componentsToAdd?.day = 6
endOfWeek = gregorian.date(byAdding: componentsToAdd!, to: beginningOfWeek!)
let components: DateComponents? = gregorian.dateComponents([.month], from: beginningOfWeek!)
let month: Int? = components?.month
let components1: DateComponents? = gregorian.dateComponents([.month], from: endOfWeek!)
let month1: Int? = components1?.month
print("\(month) - \(month1)")
showDate(start:beginningOfWeek!, end:endOfWeek!, strtMn:month!, endMn:month1!)
func showDate(start:Date, end:Date, strtMn:Int, endMn:Int) {
if strtMn == endMn{
let formatter = DateFormatter()
formatter.dateFormat = "MMM dd"
let stringFromDate: String = formatter.string(from: start)
let formatter1 = DateFormatter()
formatter1.dateFormat = "dd"
let stringFromDate1: String = formatter1.string(from: end)
print("\(stringFromDate) - \(stringFromDate1)")
lblDate.text = "\(stringFromDate) - \(stringFromDate1)"
}
else{
let formatter = DateFormatter()
formatter.dateFormat = "MMM dd"
let stringFromDate: String = formatter.string(from: start)
let formatter1 = DateFormatter()
formatter1.dateFormat = "MMM dd"
let stringFromDate1: String = formatter1.string(from: end)
print("\(stringFromDate) - \(stringFromDate1)")
lblDate.text = "\(stringFromDate) - \(stringFromDate1)"
}
}
for next and previous ....
#IBAction func week_CalendarActionEvents(_ sender: UIButton) {
let gregorian = Calendar(identifier: .gregorian)
var offsetComponents = DateComponents()
var nextStrtDate: Date?
var nextEndDate: Date?
var startDate: Date?
var endDate: Date?
startDate = beginningOfWeek
endDate = endOfWeek
if sender.tag == 1 {
offsetComponents.day = -7
}
else if sender.tag == 2 {
offsetComponents.day = 7
}
nextStrtDate = gregorian.date(byAdding: offsetComponents, to:startDate!)
startDate = nextStrtDate
beginningOfWeek = startDate
nextEndDate = gregorian.date(byAdding: offsetComponents, to: endDate!)
endDate = nextEndDate
endOfWeek = endDate
let components: DateComponents? = gregorian.dateComponents([.month], from: startDate!)
let month: Int? = components?.month
let components1: DateComponents? = gregorian.dateComponents([.month], from: endDate!)
let month1: Int? = components1?.month
print("\(month)- \(month1)")
showDate(start:startDate!, end:endDate!, strtMn:month!, endMn:month1!)
}
Swift 3+: Simple solution with extension
extension Date {
var startOfWeek: Date? {
let gregorian = Calendar(identifier: .gregorian)
guard let sunday = gregorian.date(from: gregorian.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self)) else { return nil }
return gregorian.date(byAdding: .day, value: 1, to: sunday)
}
var endOfWeek: Date? {
let gregorian = Calendar(identifier: .gregorian)
guard let sunday = gregorian.date(from: gregorian.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self)) else { return nil }
return gregorian.date(byAdding: .day, value: 7, to: sunday)
}
var yesterdayDate: Date? {
return NSCalendar.current.date(byAdding: .day, value: -1, to: noon)!
}
var tommorowDate: Date? {
return NSCalendar.current.date(byAdding: .day, value: 1, to: noon)!
}
var previousDate: Date? {
let oneDay:Double = 60 * 60 * 24
return self.addingTimeInterval(-(Double(oneDay)))
}
var nextDate: Date? {
let oneDay:Double = 60 * 60 * 24
return self.addingTimeInterval(oneDay)
}
var noon: Date {
return NSCalendar.current.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
}
var month: Int {
return Calendar.current.component(.month, from: self)
}
}
Swift 4.2
If you want to show the current week dates, here is the code.
override func viewDidLoad() {
super.viewDidLoad()
for dateIndex in 0..<7 {
guard let startWeek = Date().startOfWeek else { return }
let date = Calendar.current.date(byAdding: .day, value: dateIndex + 1, to: startWeek)
print(date)
}
}
extension Date {
var startOfWeek: Date? {
let gregorian = Calendar(identifier: .gregorian)
guard let sunday = gregorian.date(from: gregorian.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self)) else { return nil }
return gregorian.date(byAdding: .day, value: 1, to: sunday)
}
}
In swift 3.0
let cal = NSCalendar.current
//weekday
let weekday = cal.component(.weekday, from: Date())
var dateComp = cal.dateComponents([.hour, .minute, .second, .day, .month, .year], from: Date())
print(dateComp.day!)
//Start Date of the week - Sunday
dateComp.day = dateComp.day! - (weekday - 1)// start date of week
print(cal.date(from: dateComp)!)
//End Date of the Week - Saturday
dateComp = cal.dateComponents([.hour, .minute, .second, .day, .month, .year], from: Date())
dateComp.day = dateComp.day! + (7 - weekday)
print(cal.date(from: dateComp)!)
There are 3 steps to get Start date and End date of week from any region.
Find week day of current day.
func getTodayWeekDay() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEEE"
let weekDay = dateFormatter.string(from: Date())
return weekDay
}
Make emun class for subtraction and addition of days.
i.e. if current week day is Wednesday then for getting Monday of current week we have to subtract -2 from current day.
And for getting Sunday of current week we have to add 4 into current day.
enum WeekDays: String {
case monday = "Monday"
case tuesday = "Tuesday"
case wednesday = "Wednesday"
case thursday = "Thursday"
case friday = "Friday"
case saturday = "Saturday"
case sunday = "Sunday"
var daysToSubstract: Int {
switch self {
case .monday: return 0
case .tuesday: return -1
case .wednesday: return -2
case .thursday: return -3
case .friday: return -4
case .saturday: return -5
case .sunday: return -6
}
}
var daysToAdd: Int {
switch self {
case .monday: return 6
case .tuesday: return 5
case .wednesday: return 4
case .thursday: return 3
case .friday: return 2
case .saturday: return 1
case .sunday: return 0
}
}
}
Get Start-week and End-week by subtraction and addition from current day.
extension Date {
var startOfWeek: String? {
let gregorian = Calendar(identifier: .gregorian)
let startWeek = dateFormatter.string(from:gregorian.date(byAdding: .day, value: WeekDays(rawValue: getTodayWeekDay())?.daysToSubstract ?? 0, to: self)!)
print("start-week--- \(startWeek)")
return startWeek
}
var endOfWeek: String? {
let gregorian = Calendar(identifier: .gregorian)
let endWeek = dateFormatter.string(from:gregorian.date(byAdding: .day, value: WeekDays(rawValue: getTodayWeekDay())?.daysToAdd ?? 6, to: self)!)
print("end-week--- \(endWeek)")
return endWeek
}
}
You can use functions like below:
Date().startOfWeek
Date().endOfWeek

Resources