Change NSDate to Friday of that Week - objective-c

Currently I have the below code to increment my days to the next friday, however what I need is to get the friday of the current week. For example if it is last Sunday, 03/01. I would expect my response to be last Friday(02/28) not Friday(03/06).
I have checked other answers but am getting confused with how to implement a clean way to accomplish this.
+ (NSDate *)getLastFridayYearsMonthStartingDate:(NSDate *)date {
NSDateComponents *dateComponents = [[NSCalendar gregorianCalendar] components:NSYearCalendarUnit|NSCalendarUnitDay|NSCalendarUnitMonth|NSWeekdayCalendarUnit
fromDate:date];
// Set date to last year, +1 to account for previous business day
[dateComponents setYear: -1];
[dateComponents setDay:[dateComponents day]+1];
// We always want the start date to be the friday of the given week, so we will increment the difference if not
if ([dateComponents weekday] != 6) {
NSInteger daysToFriday = (13 - [dateComponents weekday]) % 7;
[dateComponents setDay:[dateComponents day]+daysToFriday];
}
NSDate *fridayDate = [[NSCalendar gregorianCalendar] dateFromComponents:dateComponents];
return fridayDate;
}

try using setWeekday to set a specific day
-(NSDate *) getFriday:(NSDate *)date {
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[cal setTimeZone:[NSTimeZone systemTimeZone]];
NSDateComponents *comp = [cal components:NSYearCalendarUnit | NSWeekCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:date];
[comp setWeekday:6];
[comp setHour:0];
[comp setMinute:0];
[comp setSecond:0];
return [cal dateFromComponents:comp];
}

Related

NSDate adding a month the right way, clipping if previous month had more days

I use this method for adding month to a date
- (NSDate *)sameDateByAddingMonths:(NSInteger)addMonths {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents * components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:self];
[components setMonth:components.month + addMonths];
return [calendar dateFromComponents:components];
}
But when the previous month in self NSDate, had more days, than it jumps on the first day next next month, like
June has 31 => self is June 31
Calling this, sets the date to 1.August, since July has 30 days
How to get this right? i thought this should behave "right" and clip on the end of month
That's what dateByAddingComponents is for:
- (NSDate *)sameDateByAddingMonths:(NSInteger)addMonths {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setMonth:addMonths];
return [calendar dateByAddingComponents:components toDate:self options:0];
}
You can use such a method to solve the issue, here I'm adding 18 months to a date:
+(NSDate *)addEighteenMonthsToDate:(NSDate *)startDate {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *newDate = [startDate copy];
newDate = [calendar dateByAddingUnit:NSCalendarUnitYear value:1 toDate:startDate options:0];
newDate = [calendar dateByAddingUnit:NSCalendarUnitMonth value:6 toDate:newDate options:0];
return newDate; }

How to get the date of the weekends?

I would like to use the date of the weekends to use it in the NSLocalNotification, but i don't how to get it, i tried to do it mathematically, but sometimes i gets a number greater than the days of the month.
Note that iOS supports several Calendars, I am not sure, if all cultures that uses those calendars have a concept of weekends and if they are always meant to have two days.
Something you also needs to deal with: even in countries that uses the Gregorian calendar a week might start with monday or sunday.
But if we assume that a weekend are equivalent to saturday and sunday, this might be helpful for you:
NSDate *referenceDate = [NSDate date];
NSDate *startOfThisWeek;
NSDate *saturday;
NSUInteger backupStartWeekday = [[NSCalendar currentCalendar] firstWeekday];
[[NSCalendar currentCalendar] setFirstWeekday:1]; // ensure week begins at sunday
[[NSCalendar currentCalendar] rangeOfUnit:NSWeekCalendarUnit
startDate:&startOfThisWeek
interval:NULL
forDate:referenceDate];
NSDateComponents *components = [[NSDateComponents alloc] init];
components.day = [[NSCalendar currentCalendar] maximumRangeOfUnit:NSWeekdayCalendarUnit].length; //the start of the next week
components.day = components.day - 2;
saturday = [[NSCalendar currentCalendar] dateByAddingComponents:components
toDate:startOfThisWeek
options:0];
[[NSCalendar currentCalendar] setFirstWeekday:backupStartWeekday];
Your first problem about getting the date can be solved as :
NSCalendar *calender=[NSCalendar currentCalendar];
NSRange daysRange=[calender rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:[NSDate date]];
NSUInteger numberOfDaysInMonth=daysRange.length;
//NSLog(#"num of days in current month : %ld",numberOfDaysInMonth);
NSDateComponents *dateComponents = [calender components:NSWeekdayCalendarUnit fromDate:[NSDate date]];
NSInteger dayCount=[dateComponents weekday];
//if today itself is saturday what you want to display? today or upcoming one... then do small changes here, for sat & sun.
NSInteger daysForSaturday=7-dayCount;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd"];
NSUInteger todaysDate = [[formatter stringFromDate:[NSDate date]]integerValue];
// NSLog(#"Today is : %#",todaysDate);
NSUInteger comingSaturday=todaysDate+daysForSaturday;
if (comingSaturday>numberOfDaysInMonth) {
comingSaturday-=numberOfDaysInMonth;
}
NSUInteger comingSunday=comingSaturday+1;
NSLog(#"Coming.. Sat is : %ld, Sun in : %ld",comingSaturday, comingSunday);

How do I implement previous/next month buttons and show dates for current month?

Scenario:
I have an expense tracking iOS Application and I am storing expenses from a expense detail view controller into a table view (with fetched results controller) that shows the list of expenses along with the category and amount and date. I do have a date attribute in my entity "Money" which is a parent entity for either an expense or an income.
Question:
What I want is to basically categorize my expenses on a monthly basis and display it as the section header title for example : (Nov 1 - Nov 30,2012) and it shows expenses amount and related stuff according to that particular month. Two buttons are provided in that view, if I would press the right button, it will increment the month by a month (Dec 1 - Dec 31, 2012) and similarly the left button would decrement the month by a month.
How would I accomplish that? I am trying the following code - which is kinda working. Suppose I have my current section header as (Nov1 - Nov 30, 2012) and when I press the left button, it gives me the section header (Oct 1 - Oct 30, 2012) which is wrong, it should be Oct 31, 2012 and not Oct 30, 2012.
- (NSDate *)firstDateOfTheMonth
{
self.startDate = [NSDate date];
NSCalendar* calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone localTimeZone]];
NSDateComponents* components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:self.startDate];
[components setDay:1];
firstDateOfTheMonth = [[calendar dateFromComponents:components] retain];
return firstDateOfTheMonth;
}
- (NSDate *)lastDateOfTheMonth
{
NSCalendar* calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone localTimeZone]];
NSDateComponents* components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:firstDateOfTheMonth];
[components setMonth:[components month]+1];
[components setDay:0];
lastDateOfTheMonth = [[calendar dateFromComponents:components] retain];
return lastDateOfTheMonth;
}
Then I have a method called "monthCalculation" in which I call the above two methods.
- (void)monthCalculation
{
[self firstDateOfTheMonth];
[self lastDateOfTheMonth];
}
Now the following code when I press the left button (to decrement the month by a month):
- (IBAction)showPreviousDates:(id)sender
{
[self monthCalculation];
NSDateComponents *dateComponents = [[[NSDateComponents alloc] init] autorelease];
[dateComponents setMonth:-1];
NSDate *newDate1 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:firstDateOfTheMonth options:0];
NSDate *newDate2 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:lastDateOfTheMonth options:0];
self.startDate = newDate1;
self.endDate = newDate2;
NSLog(#" self start date in previous mode =%#", self.startDate);
NSLog(#" self end date in previous mode =%#", self.endDate);
}
The following code when I press the right button (to increment the month by a month):
- (IBAction)showNextDates:(id)sender
{
[self monthCalculation];
NSDateComponents *dateComponents = [[[NSDateComponents alloc] init] autorelease];
[dateComponents setMonth:1];
NSDate *newDate1 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:firstDateOfTheMonth options:0];
NSDate *newDate2 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:lastDateOfTheMonth options:0];
self.startDate = newDate1;
self.endDate = newDate2;
NSLog(#" self start date in previous mode =%#", self.startDate);
NSLog(#" self end date in previous mode =%#", self.endDate);
}
Am I doing it right? or there is a better way to do achieve this? Any help will be appreciated.
Here are some methods that should do what you want:
First, in your viewDidLoad method add:
self.startDate = [NSDate date];
[self updateDateRange];
This gives you a starting point. Then, I added the following five methods (Note: previousMonthButtonPressed/nextMonthButtonPressed should be wired up to your buttons):
// Return the first day of the month for the month that 'date' falls in:
- (NSDate *)firstDayOfMonthForDate:(NSDate *)date
{
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *comps = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:date];
comps.day = 1;
return [cal dateFromComponents:comps];
}
// Return the last day of the month for the month that 'date' falls in:
- (NSDate *)lastDayOfMonthForDate:(NSDate *)date
{
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *comps = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:date];
comps.month += 1;
comps.day = 0;
return [cal dateFromComponents:comps];
}
// Move the start date back one month
- (IBAction)previousMonthButtonPressed:(id)sender {
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *comps = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:self.startDate];
comps.month -= 1;
self.startDate = [cal dateFromComponents:comps];
[self updateDateRange];
}
// Move the start date forward one month
- (IBAction)nextMonthButtonPressed:(id)sender {
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *comps = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:self.startDate];
comps.month += 1;
self.startDate = [cal dateFromComponents:comps];
[self updateDateRange];
}
// Print the new range of dates.
- (void)updateDateRange
{
NSLog(#"First day of month: %#", [self firstDayOfMonthForDate:self.startDate]);
NSLog(#"Last day of month: %#", [self lastDayOfMonthForDate:self.startDate]);
}
Try this:
- (NSDate *)lastDateOfTheMonth
{
NSCalendar* calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone localTimeZone]];
NSDateComponents* components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:firstDateOfTheMonth];
[components setMonth:[components month]+1];
NSDateComponents* offset = [[[NSDateComponents alloc] init] retain];
[offset setDay:-1];
lastDateOfTheMonth = [[calendar dateByAddingComponents:offset toDate:[components date] options:0] retain];
return lastDateOfTheMonth;
}

Getting first day of a week with NSDateComponents : changing year

Hello
I have a problem with setting a firstWeekDay, here is what I do:
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
comp = [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekCalendarUnit | NSWeekdayCalendarUnit) fromDate:targetDate];
[comp setWeekday:2];
NSDate *firstWeekDay = [gregorian dateFromComponents:comp];
If Saturday 2011-01-01 is targetDate, the firstWeekDay in my calendar appears to be Monday 2011-12-26, but in fact it should be Monday 2010-12-26. How can I make it right?
To fix this problem, Add NSYearForWeekOfYearCalendarUnit in the NSDateComponents.
Ex:
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* comps = [calendar components:NSYearForWeekOfYearCalendarUnit |NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:curDate];
[comps setWeekday:2]; // 2: monday
firstDayOfTheWeek = [calendar dateFromComponents:comps];
[comps setWeekday:7]; // 7: saturday
lastDayOfTheWeek = [calendar dateFromComponents:comps];
Try this
// adjust them for first day of previous week (Monday)
[comp setWeekday:2];
[comp setWeek:([comp week] - 1)];
Note this solution assumes the first day of the week is Monday.
Below also covers the edge case,
- (NSDate *)getFirstDayOfTheWeekFromDate:(NSDate *)givenDate
{
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:givenDate];
[components setWeekday:2]; // 1 == Sunday, 7 == Saturday
if([[calendar dateFromComponents:components] compare: curDate] == NSOrderedDescending) // if start is later in time than end
{
[components setWeek:[components week]-1];
}
return [calendar dateFromComponents:components];
}
The Swift solution (thanks #YvesJusot):
let calendar = NSCalendar.currentCalendar()
let comps = calendar.components(NSCalendarUnit.WeekOfYearCalendarUnit|NSCalendarUnit.YearCalendarUnit|NSCalendarUnit.MonthCalendarUnit|NSCalendarUnit.WeekCalendarUnit|NSCalendarUnit.WeekdayCalendarUnit, fromDate: NSDate()) as NSDateComponents
comps.setValue(2, forComponent: NSCalendarUnit.WeekdayCalendarUnit)
let monday = calendar.dateFromComponents(comps)!
println("\(monday)")
You suppose to use dynamic values instead of hardcoding 2 as Monday!
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* comps = [calendar components:NSYearForWeekOfYearCalendarUnit|NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:[NSDate date]];
comps.weekday = calendar.firstWeekday;
firstDayOfTheWeek = [calendar dateFromComponents:comps];
comps.weekday = calendar.firstWeekday - 1;
lastDayOfTheWeek = [calendar dateFromComponents:comps];
I did some changes in #JasonGarrett answer and it works for me.
let calendar = NSCalendar.currentCalendar()
let flags : NSCalendarUnit = NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitYear
let comps = calendar.components(flags, fromDate: NSDate()) as NSDateComponents
comps.setValue(2, forComponent: NSCalendarUnit.CalendarUnitWeekday)
let monday = calendar.dateFromComponents(comps)!
// Make these two methods as categories to NSDate
// Use This to get First date of the week (Monday)
- (NSDate *) getFirstDayOfWeek {
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *compOfDate = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekday) fromDate:self];
NSInteger numOfDaysToAdd = compOfDate.weekday == 1 ? -6 : (2 - compOfDate.weekday);
NSDateComponents *compToAdd = [[NSDateComponents alloc] init];
compToAdd.day = numOfDaysToAdd;
return [calendar dateByAddingComponents:compToAdd toDate:self options:0];
}
// Use This to get last date of the week (Sunday)
- (NSDate *)getLastDayOfWeek {
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *compOfDate = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekday) fromDate:self];
NSInteger numOfDaysToAdd = compOfDate.weekday == 1 ? 0 : (8 - compOfDate.weekday);
NSDateComponents *compToAdd = [[NSDateComponents alloc] init];
compToAdd.day = numOfDaysToAdd;
return [calendar dateByAddingComponents:compToAdd toDate:self options:0];
}

iPhone NSDate eg. next Friday

I want to create a function which results the date of next Friday but I have no plan how to do it. Has anyone a good hint to me ?
E.g. Get current date using NSDate, then use 'components>fromDate:' from NSCalendar to get the NSDateComponents, then add the time difference to next Friday and create a new NSDate and Bob's is your uncle.
Here is my working solution for getting the next 5 Sundays in Gregorian calendar:
self.nextBeginDates = [NSMutableArray array];
NSDateComponents *weekdayComponents = [[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate:[NSDate date]];
int currentWeekday = [weekdayComponents weekday]; //[1;7] ... 1 is sunday, 7 is saturday in gregorian calendar
NSDateComponents *comp = [[NSDateComponents alloc] init];
[comp setDay:8 - currentWeekday]; // add some days so it will become sunday
// build weeks array
int weeksCount = 5;
for (int i = 0; i < weeksCount; i++) {
[comp setWeek:i]; // add weeks
[nextBeginDates addObject:[[NSCalendar currentCalendar] dateByAddingComponents:comp toDate:[NSDate date] options:0]];
}
[comp release];
This should work
+ (NSDate *) dateForNextWeekday: (NSInteger)weekday {
NSDate *today = [[NSDate alloc] init];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
// Get the weekday component of the current date
NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit
fromDate:today];
/*
Add components to get to the weekday we want
*/
NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init];
NSInteger dif = weekday-weekdayComponents.weekday;
if (dif<=0) dif += 7;
[componentsToSubtract setDay:dif];
NSDate *beginningOfWeek = [gregorian dateByAddingComponents:componentsToSubtract
toDate:today options:0];
return beginningOfWeek;
}
Keep it simple, safe, and readable! (....KISSAR?)
#define FRIDAY 6
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dayComponent = [[NSDateComponents alloc] init];
dayComponent.day = 1;
NSDate *nextFriday = [NSDate date];
NSInteger iWeekday = [[gregorian components:NSWeekdayCalendarUnit fromDate:nextFriday] weekday];
while (iWeekday != FRIDAY) {
nextFriday = [gregorian dateByAddingComponents:dayComponent toDate:nextFriday options:0];
iWeekday = [[gregorian components:NSWeekdayCalendarUnit fromDate:nextFriday] weekday];
}
Now nextFriday has your date.
Hope this helps!
EDIT
Note that if the current date was already a Friday, it would return that instead of the next Friday. If that's undesirable just init your nextFriday to a day later (so if current date was a Friday, it would start on Saturday, forcing the next Friday. And if current date was a Thursday you'd automatically have your next Friday without needing the loop).
Here is my solution, and just to warn you, on a saturday is the friday before shown.
cheers to all
NSDate *today = [[NSDate alloc] init];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit fromDate:today];
int weekday = [weekdayComponents weekday];
int iOffsetToFryday = -weekday + 6;
weekdayComponents.weekday = iOffsetToFryday;
NSDate *nextFriday = [[NSCalendar currentCalendar] dateByAddingComponents:weekdayComponents toDate:today options:0];