How to find particular day of a month? - iphone

I've done a lot of study on NSDate NSDateFormatter and NSCalendar but cannot figure out a way to find a particular day of a month.
For example,
I want to find the date of 2nd Monday of December (10/12/2012). I know how to find number of week or number of month but cannot figure out the way to do it.
Thanks.

// Set start date of the month you want
NSString *str = #"01 - 12 - 2012";
NSDateFormatter *formatter1 = [[[NSDateFormatter alloc] init] autorelease];
[formatter1 setDateFormat:#"dd - MM - yyyy"];
NSDate *date = [formatter1 dateFromString:str];
NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDateComponents *weekdayComponents = [gregorian components:(NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:date];
// Get the weekday with sunday as one
NSInteger weekday = [weekdayComponents weekday];
int weekNumber = 2;
int dayOfweek = 2;
int x = (7 - weekday) * (weekNumber - 1) + dayOfweek;
// Add the no. of weeks - 1 or - 2 depending on the value of x.
// Also Add 1 as the start date is 1st Dec.
if(x < 7)
{
x += 7 * (weekNumber - 1) + 1;
}
else
{
x += 7 * (weekNumber - 2) + 1;
}

Try to find the particular day of the week from these codes then apply it for the month as well :)
Please refer to the following links :-
How do I get the day of the week with Cocoa Touch?
Number of days in the current month using iPhone SDK?
Hope They Help :)

Robin's and Gill's answers helped me get a solution to my problem. With some more editing I was able to get a solution to my problem.
Here is the code that I used to get the solution
-(void)findWeekDay:(NSInteger)weekDay forWeek:(NSInteger)week OfMonth:(NSInteger)month OfYear:(NSInteger)year
{
NSDateComponents *dateComp = [[NSDateComponents alloc]init];
[dateComp setYear:year];
[dateComp setMonth:month];
[dateComp setDay:1];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *firstDate=[gregorian dateFromComponents:dateComp]; //Sets first date of month.
firstDate=[self dateToGMT:firstDate];
NSLog(#"First date: %#",firstDate);
NSDateComponents *dateComp1 = [gregorian components:NSDayCalendarUnit|NSWeekdayCalendarUnit fromDate:firstDate];
NSInteger firstWeekDay=[dateComp1 weekday]; //Gets firstday of a week. 1-Sunday, 2-Monday and so on.
NSLog(#"First Week Day: %d",firstWeekDay);
NSRange daysInMonth = [gregorian rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:firstDate]; //To get number of days in that month
NSInteger x; //days to be added to first date
if (firstWeekDay < weekDay) {
x = (weekDay - firstWeekDay) + (7 * (week-1));
}
if (firstWeekDay > weekDay) {
x = (7 - firstWeekDay + weekDay) + (7 * (week-1));
}
if (firstWeekDay == weekDay) {
x = (7 * (week-1));
}
if (x > daysInMonth.length) {
NSLog(#"Invalid Date: %d",x);
}
else {
NSLog(#"Days to be added: %d",x);
NSDateComponents *dateComp2 = [[NSDateComponents alloc]init];
[dateComp2 setYear:0];
[dateComp2 setMonth:0];
[dateComp2 setDay:x];
NSDate *desiredDate = [gregorian dateByAddingComponents:dateComp2 toDate:firstDate options:0];
NSLog(#"Your desired date is: %#",desiredDate);
}
}
- (NSDate *)dateToGMT:(NSDate *)sourceDate {
NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];
NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:sourceDate];
NSDate* destinationDate = [[NSDate alloc] initWithTimeInterval:destinationGMTOffset sinceDate:sourceDate];
return destinationDate;
}
Now to find 3rd Monday of December 2012 call the method as
[self findWeekDay:2 forWeek:3 OfMonth:12 OfYear:2012];

Related

Comparing NSDate + Period

I have start date and a duration (period). For example startDate = '2014-02-12' period = 2. I desired dates 2014-02-12, 2014-02-14, 2014-02-16, .... I need to determine the current date is flagged during.
To check if the difference between the start date and the current date is an even
number of days, use NSDateComponents:
NSDate *startDate = ...;
NSDate *currentDate = [NSDate date];
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *diff = [cal components:NSDayCalendarUnit fromDate:startDate
toDate:currentDate options:0];
NSInteger days = diff.day;
if (days % 2 == 0) {
// even number of days between start date and current date
}
You can get the desired dates using
- (id)dateByAddingTimeInterval:(NSTimeInterval)seconds
with seconds = period*3600*24
Calc the days from startDate to givenData, check the result whether it can be divisible by the period.
+ (NSInteger)daysWithinEraFromDate:(NSDate *)startDate toDate:(NSDate *)endDate {
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setTimeZone:[NSTimeZone localTimeZone]];
// for timezone issue
NSDate *newDate1 = [startDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];
NSDate *newDate2 = [endDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];
NSInteger startDay = [gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:newDate1];
NSInteger endDay = [gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:newDate2];
return endDay - startDay;
}

How to implement previous next day buttons to change the date in iphone

As shown in the above page I have a date (current date by default) on a label. In the format of MM dd.
I have two buttons to change the date next day & the previous day.
How should I implement change the date by using these buttons?
Any tutorial / advice (I don't think there is any involvement of datepicker in this)
Use these two functions to get previous date and next date and then use the returned date and use only month and year to display on your label.
+ (NSDate *) getDate:(NSDate *)fromDate daysAgo:(NSUInteger)days
{
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
dateComponents.day = -1*days;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *previousDate = [calendar dateByAddingComponents:dateComponents
toDate:fromDate
options:0];
[dateComponents release];
return previousDate;
}
+ (NSDate *) getDate:(NSDate *)fromDate daysAhead:(NSUInteger)days
{
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
dateComponents.day = days;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *previousDate = [calendar dateByAddingComponents:dateComponents
toDate:fromDate
options:0];
[dateComponents release];
return previousDate;
}
Try these methods
- (NSDate *) dateByAddingDays: (int) dDays : (NSDate*)presntdate
{
NSTimeInterval aTimeInterval = [presntdate timeIntervalSinceReferenceDate] + 86400 * dDays;
NSDate *newDate = [NSDate dateWithTimeIntervalSinceReferenceDate:aTimeInterval];
return newDate;
}
- (NSDate *) dateBySubtractingDays: (int) dDays : (NSDate*)presntdate
{
return [self dateByAddingDays: dDays*-1 :presntdate];
}

Check whether a specified date is today, yesterday, or a future date

I have one query regarding NSDate. I have a date i.e. "2011-10-04 07:36:38 +0000", and I want to check if this date is yesterday, or today or a future date.
How would I go about this?
Try this:
Note: Change the date format as per your need.
NSDateFormatter* df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"MM/dd/yyyy"];
NSDate* enteredDate = [df dateFromString:#"10/04/2011"];
NSDate * today = [NSDate date];
NSComparisonResult result = [today compare:enteredDate];
switch (result)
{
case NSOrderedAscending:
NSLog(#"Future Date");
break;
case NSOrderedDescending:
NSLog(#"Earlier Date");
break;
case NSOrderedSame:
NSLog(#"Today/Null Date Passed"); //Not sure why This is case when null/wrong date is passed
break;
}
See Apple's documentation on date calculations:
NSDate *startDate = ...;
NSDate *endDate = ...;
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSUInteger unitFlags = NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *components = [gregorian components:unitFlags
fromDate:startDate
toDate:endDate options:0];
NSInteger months = [components month];
NSInteger days = [components day];
If days is between +1 and -1 then your date is a candidate for being "today". Obviously you'll need to think about how you handle hours. Presumably the easiest thing would be to set all dates to be 00:00.00 hours on the day in question (truncate the date using an approach like this), and then use those values for the calculation. That way you'd get 0 for today, -1 for yesterday, +1 for tomorrow, and any other value would likewise tell you how far things were in the future or the past.
Use any of the folowing according to ur need,
– earlierDate:
– laterDate:
– compare:
Refer this http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/Reference/Reference.html
-(NSString*)timeAgoFor:(NSString*)tipping_date
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd"];
NSDate *date = [dateFormatter dateFromString:tipping_date];
NSString *key = #"";
NSTimeInterval ti = [date timeIntervalSinceDate:[NSDate date]];
key = (ti > 0) ? #"Left" : #"Ago";
ti = ABS(ti);
NSDate * today = [NSDate date];
NSComparisonResult result = [today compare:date];
if (result == NSOrderedSame) {
return[NSString stringWithFormat:#"Today"];
}
else if (ti < 86400 * 2) {
return[NSString stringWithFormat:#"1 Day %#",key];
}else if (ti < 86400 * 7) {
int diff = round(ti / 60 / 60 / 24);
return[NSString stringWithFormat:#"%d Days %#", diff,key];
}else {
int diff = round(ti / (86400 * 7));
return[NSString stringWithFormat:#"%d Wks %#", diff,key];
}
}

Create Event with NSDate

is there any way to create events for NSDate ? here is my code
NSDate *date = [NSDate date];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"MMMM d, yyyy"];
NSString *dateStr = [dateFormatter stringFromDate:date];
myDate.text = dateStr;
for example if date = 12 FEB ;
myDate .text = #"Mother Day";
something like this
sure it is. You have to split the date into day and month using NSDateComponents
You could write a method like this:
- (BOOL)date:(NSDate *)date isSameAsDay:(NSInteger)day andMonth:(NSInteger)month {
NSUInteger dateFlags = NSDayCalendarUnit | NSMonthCalendarUnit;
NSDateComponents *components = [[NSCalendar currentCalendar] components:dateFlags fromDate:date];
if ([components day] == day && [components month] == month) {
return YES;
}
return NO;
}
and you would use it like this
if ([self date:[NSDate date] isSameAsDay:12 andMonth:2]) {
myDate.text = #"Mother Day";
}
This should do it:
NSDate *today = [NSDate date]; // Get ref to todays date
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdayComponents =
[gregorian components:(NSWeekdayOrdinalCalendarUnit | NSWeekdayCalendarUnit | NSMonthCalendarUnit) fromDate:today];
NSInteger weekday = [weekdayComponents weekday]; // Sun == 1, Mon == 2, Tue...
NSInteger weekdayOrdinal = [weekdayComponents weekdayOrdinal]; // First weekday month == 1 etc...
NSInteger month = [weekdayComponents month];
NSLog (#"%i %i %i", weekday, weekdayOrdinal, month);
// Mothers day is every second Sunday of May so weekday == 1, weekdayOrdinal == 2, month == 5
if ((weekday == 1) && (weekdayOrdinal == 2) && (month == 5)) {
NSLog (#"It's mothers day!");
}
[gregorian release];

How do I break down an NSTimeInterval into year, months, days, hours, minutes and seconds on iPhone?

I have a time interval that spans years and I want all the time components from year down to seconds.
My first thought is to integer divide the time interval by seconds in a year, subtract that from a running total of seconds, divide that by seconds in a month, subtract that from the running total and so on.
That just seems convoluted and I've read that whenever you are doing something that looks convoluted, there is probably a built-in method.
Is there?
I integrated Alex's 2nd method into my code.
It's in a method called by a UIDatePicker in my interface.
NSDate *now = [NSDate date];
NSDate *then = self.datePicker.date;
NSTimeInterval howLong = [now timeIntervalSinceDate:then];
NSDate *date = [NSDate dateWithTimeIntervalSince1970:howLong];
NSString *dateStr = [date description];
const char *dateStrPtr = [dateStr UTF8String];
int year, month, day, hour, minute, sec;
sscanf(dateStrPtr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &sec);
year -= 1970;
NSLog(#"%d years\n%d months\n%d days\n%d hours\n%d minutes\n%d seconds", year, month, day, hour, minute, sec);
When I set the date picker to a date 1 year and 1 day in the past, I get:
1 years 1 months 1 days 16 hours 0
minutes 20 seconds
which is 1 month and 16 hours off. If I set the date picker to 1 day in the past, I am off by the same amount.
Update: I have an app that calculates your age in years, given your birthday (set from a UIDatePicker), yet it was often off. This proves there was an inaccuracy, but I can't figure out where it comes from, can you?
Brief Description
Just another approach to complete the answer of JBRWilkinson but adding some code. It can also offers a solution to Alex Reynolds's comment.
Use NSCalendar method:
(NSDateComponents *)components:(NSUInteger)unitFlags fromDate:(NSDate *)startingDate toDate:(NSDate *)resultDate options:(NSUInteger)opts
"Returns, as an NSDateComponents object using specified components, the difference between two supplied dates". (From the API documentation).
Create 2 NSDate whose difference is the NSTimeInterval you want to break down. (If your NSTimeInterval comes from comparing 2 NSDate you don't need to do this step, and you don't even need the NSTimeInterval, just apply the dates to the NSCalendar method).
Get your quotes from NSDateComponents
Sample Code
// The time interval
NSTimeInterval theTimeInterval = ...;
// Get the system calendar
NSCalendar *sysCalendar = [NSCalendar currentCalendar];
// Create the NSDates
NSDate *date1 = [[NSDate alloc] init];
NSDate *date2 = [[NSDate alloc] initWithTimeInterval:theTimeInterval sinceDate:date1];
// Get conversion to months, days, hours, minutes
NSCalendarUnit unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit;
NSDateComponents *breakdownInfo = [sysCalendar components:unitFlags fromDate:date1 toDate:date2 options:0];
NSLog(#"Break down: %i min : %i hours : %i days : %i months", [breakdownInfo minute], [breakdownInfo hour], [breakdownInfo day], [breakdownInfo month]);
This code is aware of day light saving times and other possible nasty things.
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorianCalendar components: (NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit )
fromDate:startDate
toDate:[NSDate date]
options:0];
NSLog(#"%ld", [components year]);
NSLog(#"%ld", [components month]);
NSLog(#"%ld", [components day]);
NSLog(#"%ld", [components hour]);
NSLog(#"%ld", [components minute]);
NSLog(#"%ld", [components second]);
From iOS8 and above you can use NSDateComponentsFormatter
It has methods to convert time difference in user friendly formatted string.
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleFull;
NSLog(#"%#", [formatter stringFromTimeInterval:1623452]);
This gives the output - 2 weeks, 4 days, 18 hours, 57 minutes, 32 seconds
Convert your interval into an NSDate using +dateWithIntervalSince1970, get the date components out of that using NSCalendar's -componentsFromDate method.
SDK Reference
This works for me:
float *lenghInSeconds = 2345.234513;
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:lenghInSeconds];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
[formatter setDateFormat:#"HH:mm:ss"];
NSLog(#"%#", [formatter stringFromDate:date]);
[formatter release];
The main difference here is that you need to adjust for the timezone.
Or there is my class method. It doesn't handle years, but that could easily be addedn though it's better for small timelaps like days, hours and minutes. It take plurals into account and only shows what's needed:
+(NSString *)TimeRemainingUntilDate:(NSDate *)date {
NSTimeInterval interval = [date timeIntervalSinceNow];
NSString * timeRemaining = nil;
if (interval > 0) {
div_t d = div(interval, 86400);
int day = d.quot;
div_t h = div(d.rem, 3600);
int hour = h.quot;
div_t m = div(h.rem, 60);
int min = m.quot;
NSString * nbday = nil;
if(day > 1)
nbday = #"days";
else if(day == 1)
nbday = #"day";
else
nbday = #"";
NSString * nbhour = nil;
if(hour > 1)
nbhour = #"hours";
else if (hour == 1)
nbhour = #"hour";
else
nbhour = #"";
NSString * nbmin = nil;
if(min > 1)
nbmin = #"mins";
else
nbmin = #"min";
timeRemaining = [NSString stringWithFormat:#"%#%# %#%# %#%#",day ? [NSNumber numberWithInt:day] : #"",nbday,hour ? [NSNumber numberWithInt:hour] : #"",nbhour,min ? [NSNumber numberWithInt:min] : #"00",nbmin];
}
else
timeRemaining = #"Over";
return timeRemaining;
}
NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
// format: YYYY-MM-DD HH:MM:SS ±HHMM
NSString *dateStr = [date description];
NSRange range;
// year
range.location = 0;
range.length = 4;
NSString *yearStr = [dateStr substringWithRange:range];
int year = [yearStr intValue] - 1970;
// month
range.location = 5;
range.length = 2;
NSString *monthStr = [dateStr substringWithRange:range];
int month = [monthStr intValue];
// day, etc.
...
- (NSString *)convertTimeFromSeconds:(NSString *)seconds {
// Return variable.
NSString *result = #"";
// Int variables for calculation.
int secs = [seconds intValue];
int tempHour = 0;
int tempMinute = 0;
int tempSecond = 0;
NSString *hour = #"";
NSString *minute = #"";
NSString *second = #"";
// Convert the seconds to hours, minutes and seconds.
tempHour = secs / 3600;
tempMinute = secs / 60 - tempHour * 60;
tempSecond = secs - (tempHour * 3600 + tempMinute * 60);
hour = [[NSNumber numberWithInt:tempHour] stringValue];
minute = [[NSNumber numberWithInt:tempMinute] stringValue];
second = [[NSNumber numberWithInt:tempSecond] stringValue];
// Make time look like 00:00:00 and not 0:0:0
if (tempHour < 10) {
hour = [#"0" stringByAppendingString:hour];
}
if (tempMinute < 10) {
minute = [#"0" stringByAppendingString:minute];
}
if (tempSecond < 10) {
second = [#"0" stringByAppendingString:second];
}
if (tempHour == 0) {
NSLog(#"Result of Time Conversion: %#:%#", minute, second);
result = [NSString stringWithFormat:#"%#:%#", minute, second];
} else {
NSLog(#"Result of Time Conversion: %#:%#:%#", hour, minute, second);
result = [NSString stringWithFormat:#"%#:%#:%#",hour, minute, second];
}
return result;
}
Here's another possibility, somewhat cleaner:
NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSString *dateStr = [date description];
const char *dateStrPtr = [dateStr UTF8String];
// format: YYYY-MM-DD HH:MM:SS ±HHMM
int year, month, day, hour, minutes, seconds;
sscanf(dateStrPtr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minutes, &seconds);
year -= 1970;