Showing "past" and "upcoming" sections UITableView with FetchedResultsController - ios

I'm having a bit of difficulty grouping my table view by past and upcoming. This would be determined by a date field in my Core Data model. So all items with a date > today would be upcoming, and all with a date < today would be considered past. Any insight into this would be greatly appreciated.

You can use this function in your entities class:
-(NSString*)dateToStringForSectionTitels{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
NSString *formattedDateString;
[dateFormatter locale];
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:[NSDate date]];
NSDate *today = [cal dateFromComponents:components];
components = [cal components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:self.startDate];
NSDate *otherDate = [cal dateFromComponents:components];
if([today isEqualToDate:otherDate]) {
formattedDateString = #"Today";
}else{
[dateFormatter setDateStyle:NSDateFormatterShortStyle];
formattedDateString = [dateFormatter stringFromDate:self.startDate];
}
NSTimeInterval distanceBetweenDates = [self.startDate timeIntervalSinceDate:[NSDate date]];
double secondsInAnMinute = 60;
NSInteger minutsBetweenDates = distanceBetweenDates / secondsInAnMinute;
if (minutsBetweenDates<30) {
formattedDateString = #"Starting Soon";
}else if(minutsBetweenDates<0){
formattedDateString = #"In the past";
}
return formattedDateString;
}
It will return
The date in a string if the event is in the future
"Today" if the event is today.
"Starting soon" if the event is starting in 30 minutes - (You can range it to what ever you wish.
"In the past" if the event is in the past.
Then just pass the "dateToStringForSectionTitels" to your fetch result controller.
Good luck.

Related

Get days between days

Before giving downvote, comment the reason
I have created a UIDatePicker with minimum & maximum date values (i.e. 6 months of date picker) Now, i need to get 7 days from selected date. There i need to check the conditions,
If date is today date i need to get 7 days from today onwards
If date is last date (i.e. last date of picker) need to get last 7 days including last day
If date is middle of today's date & last date i need to get last 3 days, next 3 days including today date. And, also while getting last & next 3 days it shouldn't get exceed with picker's date limit.
Here's my code snippet:
- (void)addDays:(NSInteger)range {
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"dd-MM-yyyy"];
NSDate *startDate = self.selectedDate;
for (int x = 0; x <= range; x++) {
NSLog(#"%#", [dateFormat stringFromDate:startDate]);
startDate = [startDate dateByAddingTimeInterval:(60 * 60 * 24)];
}
}
- (void)minusDays:(NSInteger)range {
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"dd-MM-yyyy"];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *comps = [NSDateComponents new];
for (NSInteger i=0; i<range; i++) {
comps.day += -1;
NSDate *date = [calendar dateByAddingComponents:comps toDate:self.selectedDate options:0];
NSDateComponents *components = [calendar components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:date];
NSLog(#"%#", [dateFormat stringFromDate:[calendar dateFromComponents:components]]);
}
}
- (void)calculateDateRange {
if ([dateArray count] > 0) {
[dateArray removeAllObjects];
}
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *lastcomponents = [calendar components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:[NSDate date]];
lastcomponents.month += 6;
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:#"yyyy/MM/dd"];
NSDate *currentDate = [NSDate date];
NSDate *selectedD = self.selectedDate;
NSDate *endDate = [calendar dateFromComponents:lastcomponents];
NSDate *fromDate;
NSDate *toDate;
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&fromDate interval:NULL forDate:currentDate];
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&toDate interval:NULL forDate:selectedD];
NSDateComponents *difference = [calendar components:NSDayCalendarUnit fromDate:fromDate toDate:toDate options:0];
NSInteger first = [difference day];
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&fromDate interval:NULL forDate:selectedD];
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&toDate interval:NULL forDate:endDate];
NSDateComponents *difference2 = [calendar components:NSDayCalendarUnit fromDate:fromDate toDate:toDate options:0];
NSInteger second = [difference2 day];
if ((first == 0 || first < 3) && second > 7) {
[self addDays:7];
} else if (first >= 3 && second > 7) {
[self minusDays:3];
[self addDays:3];
}else if (second == 7 || second < 7) {
[self minusDays:7];
}
}
This is working fine. But, can't get exact last & previous days.
Anyone has idea on this?
My interpretation of your needs
You have a date picker. When a date is picked you need to create a 7 day range around that selected date.
So, if the selected date is 15/11/2014 then you want 3 days either side so...
12/11/2014 - 18/11/2014.
However, the date range cannot exceed the limits of the date picker. So if the minimum date on the date picker is set to 14/11/2014 then (in the above example) the date range would be...
14/11/2014 - 21/11/2014
Even after your additional explanation this is still my interpretation. And my code does exactly this.
Solution
You CANNOT use 60*60*24 to mean one day. This is just wrong. When dealing with dates you should always be using NSDateComponents and NSCalendar.
Also, break down your problem into small steps. There is no reason to do everything in one giant function.
OK I guess you have a datePicker action somewhere so I'd code it like this...
- (void)datePickerDateChanged
{
NSDate *minimumDate = self.datePicker.minimumDate;
NSDate *maximumDate = self.datePicker.maximumDate;
NSDate *selectedDate = self.datePicker.date;
NSDate *startDate;
NSDate *endDate;
if ([self numberOfDaysFromDate:minimumDate toDate:selectedDate] < 3) {
// get 7 days after minimumDate
startDate = minimumDate;
endDate = [self dateByAddingDays:6 toDate:minimumDate];
} else if ([self numberOfDaysFromDate:selectedDate toDate:maximumDate] < 3) {
// get 7 days before maximumDate
startDate = [self dateByAddingDays:-6 toDate:maximumDate];
endDate = maximumDate;
} else {
// get 3 days before and 3 days after selectedDate
startDate = [self dateByAddingDays:-3 toDate:selectedDate];
endDate = [self dateByAddingDays:3 toDate:selectedDate];
}
// Here startDate and endDate define your date range.
}
- (NSDate *)dateByAddingDays:(NSInteger)days toDate:(NSDate *)date
{
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [NSDateComponents new];
components.day = days;
return [calendar dateByAddingComponents:components toDate:date options:0];
}
- (NSInteger)numberOfDaysFromDate:(NSDate *)fromDate toDate:(NSDate *)toDate
{
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSDayCalendarUnit fromDate:fromDate toDate:toDate options:0];
// always return positive. We just want magnitude of days.
return components.day > 0 ? components.day : -components.day;
}
This is untested and just a first attempt.

Weekday of first day of month

I need to get the weekday of the first day of the month. For example, for the current month September 2013 the first day falls on Sunday.
At first, get the first day of current month (for example):
NSDate *today = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorian components:(NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit) fromDate:today];
components.day = 1;
NSDate *firstDayOfMonth = [gregorian dateFromComponents:components];
Then use NSDateFormatter to print it as a weekday:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEEE"];
NSLog(#"%#", [dateFormatter stringFromDate:firstDayOfMonth]);
P.S. also take a look at Date Format Patterns
Here is the solution to getting the weekday name of the first day in the current month
NSDateComponents *weekdayComps = [[NSDateComponents alloc] init];
weekdayComps = [calendar.currentCalendar components:calendar.unitFlags fromDate:calendar.today];
weekdayComps.day = 1;
NSDateFormatter *weekDayFormatter = [[NSDateFormatter alloc]init];
[weekDayFormatter setDateFormat:#"EEEE"];
NSString *firstweekday = [weekDayFormatter stringFromDate:[calendar.currentCalendar dateFromComponents:weekdayComps]];
NSLog(#"FIRST WEEKDAY: %#", firstweekday);
For the weekday index, use this
NSDate *weekDate = [calendar.currentCalendar dateFromComponents:weekdayComps];
NSDateComponents *components = [calendar.currentCalendar components: NSWeekdayCalendarUnit fromDate: weekDate];
NSUInteger weekdayIndex = [components weekday];
NSLog(#"WEEKDAY INDEX %i", weekdayIndex);
You can also increment or decrement the month if needed.
Depending on the output you need you may use NSDateFormatter (as it was already said) or you may use NSDateComponents class. NSDateFormatter will give you a string representation, NSDateComponents will give you integer values. Method weekday may do what you want.
NSDateComponents *components = ...;
NSInteger val = [components weekday];
For Swift 4.2
First:
extension Calendar {
func startOfMonth(_ date: Date) -> Date {
return self.date(from: self.dateComponents([.year, .month], from: date))!
}
}
Second:
self.firstWeekDay = calendar.component(.weekday, from: calendar.startOfMonth(Date()))

Get time from pressed button (hold pressed)

When trying to get the time, I am not getting the expected value.
When I ran this, the time was 19:59. And in the timeDifferenceString, the Value was 71976.894206.
I think that this is the current time.
I calculate 71976 / 3600 = 19,99 h
0,99 * 60 = 59,4 m
0,4 * 60 = 24 s
So I get the time 19:59:24 o'clock. But I want get the difference between the first time and the second time and not the current time in seconds.
I want only get the time when I (hold) pressed the button
and the time that the button is not pressed (by starting the first time if I press on the button and stopped if I press on an other button).
- (IBAction)pressTheButton:(id)sender {
NSDate * now = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"hh:mm:ss:SSS"];
NSString *currentTime = [formatter stringFromDate:now];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components; //= [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:now];
[components setHour:10];
NSDate* firstDate = [NSDate date];
NSString *getTime = [formatter stringFromDate:now];
getTime = [formatter stringFromDate:firstDate];
if (iX==0)
{
components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:now];
firstDate = [calendar dateFromComponents:components];
getTime = [formatter stringFromDate:firstDate];
//firstDate = [NSDate date];//[dateFormatter dateFromString:#"00:01:00:090"];
}
components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:now];
//NSDate* secondDate = [dateFormatter dateFromString:#"10:01:02:007"];
NSDate * secondDate = [calendar dateFromComponents:components];
getTime = [formatter stringFromDate:firstDate];
NSTimeInterval timeDifference = [firstDate timeIntervalSinceDate:secondDate];
NSString *timeDifferenceString = [NSString stringWithFormat:#"%f", timeDifference];
timeDiff[iX] = [timeDifferenceString intValue];
[timeLabel setText:timeDifferenceString];
iX++;
}
If you have a better solution for my problem pleas help me.
Look at UIControlEventTouchDown, UIControlEventTouchUpInside here: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIControl_Class/Reference/Reference.html
Then I suppose you want to store an NSDate of when you pressed down in some sort of ivar or property (UIControlEventTouchDown) and another one when you release the button (UIControlEventTouchUpInside or UIControlEventTouchUpOutside) and then call -timeIntervalSinceDate: on that date. So it would look roughly like this:
- (IBAction)pressedDown:(id)sender {
self.pressedDownDate = [NSDate date];
}
- (IBAction)touchedUp:(id)sender {
NSDate *now = [NSDate date];
NSLog(#"Time passed: %d", [now timeIntervalSinceDate:self.pressedDownDate]);
}

Get weeks date in IOS SDK

I want to get the current & next week dates with day name.
i.e. If today's date is 28-06-2013 (Friday) then I want to get the dates from 23-06-2013(sunday) to 29-06-2013 (Saturday) as the this current week.
for next week
I want to get dates from 30-06-2013(sunday) to 06-07-2013 (saturday).
How can I do this?
Thank you,
Here is sample code that does the trick.
-(NSArray*)daysThisWeek
{
return [self daysInWeek:0 fromDate:[NSDate date]];
}
-(NSArray*)daysNextWeek
{
return [self daysInWeek:1 fromDate:[NSDate date]];
}
-(NSArray*)daysInWeek:(int)weekOffset fromDate:(NSDate*)date
{
NSCalendar *calendar = [NSCalendar currentCalendar];
//ask for current week
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps=[calendar components:NSWeekCalendarUnit|NSYearCalendarUnit fromDate:date];
//create date on week start
NSDate* weekstart=[calendar dateFromComponents:comps];
if (weekOffset>0) {
NSDateComponents* moveWeeks=[[NSDateComponents alloc] init];
moveWeeks.week=1;
weekstart=[calendar dateByAddingComponents:moveWeeks toDate:weekstart options:0];
}
//add 7 days
NSMutableArray* week=[NSMutableArray arrayWithCapacity:7];
for (int i=1; i<=7; i++) {
NSDateComponents *compsToAdd = [[NSDateComponents alloc] init];
compsToAdd.day=i;
NSDate *nextDate = [calendar dateByAddingComponents:compsToAdd toDate:weekstart options:0];
[week addObject:nextDate];
}
return [NSArray arrayWithArray:week];
}
I was going to copy and paste an answer, but I'd suggest going and reading this post: Current Week Start and End Date. It looks like it'll help you achieve what you want to.
Something like this perhaps:
NSDate *now = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger weekNumber = [[calendar components: NSWeekCalendarUnit fromDate:now] week];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comp = [gregorian components:NSYearCalendarUnit fromDate:now];
[comp setWeek:weekNumber]; //Week number.
int i;
for (i = 1; i < 8; i=i+1){
[comp setWeekday:i]; //First day of the week. Change it to 7 to get the last date of the week
NSDate *resultDate = [gregorian dateFromComponents:comp];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"EEEE MMMM d, yyyy"];
NSString *myDateString = [formatter stringFromDate:resultDate];
NSLog(#"%#",myDateString);
}
Use NSDateComponents to find out the day of the week and then to find the date required before and after it.
Umm, I'm not an expert on this or anything, but a dumb way to do this is to first be able to recognize the day of the week from NSDate. Then you could add in if statements then the if statements could add and subtract the dates and nslog or printf each of them. Or I think there is a way by accessing the ios calendar.
okay so the above pretty much said and did more than what I said. Yeah go check the link on the post before me.
Use an NSCalendar instance to convert your start NSDate instance into an NSDateComponents instance, add 1 day to the NSDateComponents and use the NSCalendar to convert that back to an NSDate instance. Repeat the last two steps until you reach your end date.
NSDate *currentDate = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:1];
NSDate *nextDate = [calendar dateByAddingComponents:comps toDate:currentDate options:0];
Or else find start date and end date. like
NSDate *startDate = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:7];
NSDate *endDate = [calendar dateByAddingComponents:comps toDate:currentDate options:0];
then,
NSDate nextDate;
for ( nextDate = startDate ; [nextDate compare:endDate] < 0 ; nextDate = [nextDate addTimeInterval:24*60*60] ) {
// use date
}

Display NSDates in terms of week

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 for a given week, a month, or year and display it as the section header title for example : (Oct 1- Oct 7, 2012) and it shows expenses amount and related stuff according to that particular week. Two buttons are provided in that view, if I would press the right button, it will increment the week by a week (Oct 1- Oct 7, 2012 now shows Oct8 - Oct 15, 2012) and similarly the left button would decrement the week by a week.
How would I accomplish that? I am trying the following code - doesn't work.
- (void)weekCalculation
{
NSDate *today = [NSDate date]; // present date (current date)
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* comps = [calendar components:NSYearForWeekOfYearCalendarUnit |NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:today];
[comps setWeekday:1]; // 1: Sunday
firstDateOfTheWeek = [[calendar dateFromComponents:comps] retain];
[comps setWeekday:7]; // 7: Saturday
lastDateOfTheWeek = [[calendar dateFromComponents:comps] retain];
NSLog(#" first date of week =%#", firstDateOfTheWeek);
NSLog(#" last date of week =%#", lastDateOfTheWeek);
firstDateOfWeek = [dateFormatter stringFromDate:firstDateOfTheWeek];
lastDateOfWeek = [dateFormatter stringFromDate:lastDateOfTheWeek];
}
Code for incrementing date -
- (IBAction)showNextDates:(id)sender
{
int addDaysCount = 7;
NSDateComponents *dateComponents = [[[NSDateComponents alloc] init] autorelease];
[dateComponents setDay:addDaysCount];
NSDate *newDate1 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:firstDateOfTheWeek options:0];
NSDate *newDate2 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:lastDateOfTheWeek options:0];
NSLog(#" new dates =%# %#", newDate1, newDate2);
}
Suppose the week shows like this (Nov4, 2012 - Nov10, 2012) and I press the increment button, I see in the console, date changes to Nov11,2012 and Nov.17, 2012 which is right but if I press the increment button again, it shows the same date again (Nov 11, 2012 and Nov.17, 2012).
Please help me out here.
Declare currentDate as an #property in your class. And try this.
#property(nonatomic, retain) NSDate *currentDate;
Initially set
self.currentDate = [NSDate date];
before calling this method.
- (void)weekCalculation
{
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* comps = [calendar components:NSYearForWeekOfYearCalendarUnit |NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:self.currentDate];
[comps setWeekday:1]; // 1: Sunday
firstDateOfTheWeek = [[calendar dateFromComponents:comps] retain];
[comps setWeekday:7]; // 7: Saturday
lastDateOfTheWeek = [[calendar dateFromComponents:comps] retain];
NSLog(#" first date of week =%#", firstDateOfTheWeek);
NSLog(#" last date of week =%#", lastDateOfTheWeek);
firstDateOfWeek = [dateFormatter stringFromDate:firstDateOfTheWeek];
lastDateOfWeek = [dateFormatter stringFromDate:lastDateOfTheWeek];
}
Once the view is loaded self.currentDate value should be updated from showNextDates. Make sure it is not getting reset anywhere else.
- (IBAction)showNextDates:(id)sender
{
int addDaysCount = 7;
NSDateComponents *dateComponents = [[[NSDateComponents alloc] init] autorelease];
[dateComponents setDay:addDaysCount];
NSDate *newDate1 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:firstDateOfTheWeek options:0];
NSDate *newDate2 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:lastDateOfTheWeek options:0];
NSLog(#" new dates =%# %#", newDate1, newDate2);
self.currentDate = newDate1;
}
I had needed similar thing in one of my old projects and achieved it via the code below. It sets this weeks date to an NSDate variable and adds/removes 7 days from day component in each button click. Here is the code:
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
NSDate *date = [NSDate date];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit|NSWeekdayCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:date ];
//
[components setDay:([components day] - ([components weekday] )+2)];
self.currentDate = [calendar dateFromComponents:components];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"dd.MM.yyyy HH:mm:ss";
self.datelabel.text = [formatter stringFromDate:self.currentDate];
The code above calculates this week start and sets it to currentDate variable. I Have two UIButtons with UIActions named prevClick and nextClick which calls the method that sets the next or previous weekstart:
- (IBAction)prevClick:(id)sender {
[self addRemoveWeek:NO];
}
-(void)addRemoveWeek:(BOOL)add{
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit|NSWeekdayCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:self.currentDate ];
components.day = add?components.day+7:components.day-7;
self.currentDate = [calendar dateFromComponents:components];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"dd.MM.yyyy HH:mm:ss";
self.datelabel.text = [formatter stringFromDate:self.currentDate];
}
- (IBAction)nextClk:(id)sender {
[self addRemoveWeek: YES];
}

Resources