I tried the following code, but I do not get a condition where the date is in next week. How will I know that the date which is parameter in the function falls in next week? Following code always returns 1.
- (NSInteger)thisW:(NSDate *)date
{
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *todaysComponents =
[gregorian components:NSYearCalendarUnit fromDate:[NSDate date]];
NSUInteger todaysWeek = [todaysComponents weekOfYear];
NSDateComponents *otherComponents =
[gregorian components:NSYearCalendarUnit fromDate:date];
NSUInteger datesWeek = [otherComponents weekOfYear];
//NSLog(#"Date %#",date);
if(todaysWeek==datesWeek){
//NSLog(#"Date is in this week");
return 1;
}else if(todaysWeek+1==datesWeek){
//NSLog(#"Date is in next week");
return 2;
} else {
return 0;
}
}
You need to pass NSCalendarUnitWeekOfYear when extracting date components:
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *todaysComponents = [gregorian components:NSCalendarUnitWeekOfYear fromDate:[NSDate date]];
NSUInteger todaysWeek = [todaysComponents weekOfYear];
NSDateComponents *otherComponents = [gregorian NSCalendarUnitWeekOfYear fromDate:date];
NSUInteger datesWeek = [otherComponents weekOfYear];
Using datecomponents for week calculations will give you problems when the dates are close to year's end, i.e. "The first week of the year is designated to be the week containing the first Thursday of the year.(ISO 8601)"
I find it easier to compare dates with certain granularity, weekly in this case (the following code detects if a date is more than one week in the past, last week, this week, next week or further in the future)
-(EventWeekRange)numberOfWeeksFromTodayToEvent:(NSDate *)eventDate {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSComparisonResult comparison = [calendar compareDate:[NSDate date] toDate:eventDate toUnitGranularity:NSCalendarUnitWeekOfYear];
if (comparison == NSOrderedSame) {
return RangeThisWeek;
} else if (comparison == NSOrderedAscending) { // The event date is in the future
// Advance today's date one week to check if this new date is in the same week as the event
NSDate *todaysNextWeek = [[NSDate date]dateByAddingTimeInterval:60*60*24*7];
if ([calendar compareDate:todaysNextWeek toDate:eventDate toUnitGranularity:NSCalendarUnitWeekOfYear] == NSOrderedSame) {
return RangeNextWeek;
} else {
return RangeLater;
}
} else { // The event date is in the past
// Advance the event's date one week to check if this new date is in the same week as today
NSDate *eventsNextWeek = [eventDate dateByAddingTimeInterval:60*60*24*7];
if ([calendar compareDate:eventsNextWeek toDate:[NSDate date] toUnitGranularity:NSCalendarUnitWeekOfYear] == NSOrderedSame) {
return RangeLastWeek;
} else {
return RangeEarlier;
}
}
}
Related
I have try to get next week start and end date but I have got current week start and end date.How can get next week start and end date in Objective-c.
You can get all dates of this week and next week using following code:-
NSArray * allDatesOfThisWeek = [self daysThisWeek];
NSArray * allDatesOfNextWeek = [self daysNextWeek];
Following methods are used for calculating dates of this week:-
-(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];
NSDateComponents* moveWeeks=[[NSDateComponents alloc] init];
moveWeeks.weekOfYear=weekOffset;
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];
}
If you want to get dates of next to next week from today, then pass weekOffset=2 like this:-
NSArray * allDatesOfNextToNextWeek = [self daysInWeek:2 fromDate:now];
If you want to get dates of previous week from today, then pass weekOffset=-1 like this:-
NSArray * allDatesOfPreviousWeek = [self daysInWeek:-1 fromDate:now];
Hope, this is what you're looking for. Any concern get back to me.
NSCalendar contains dedicated methods to do that for example nextDateAfterDate:matchingUnit:value:options: and dateByAddingComponents:toDate:options:
// Get the current calendar
NSCalendar *calendar = [NSCalendar currentCalendar];
// Get the next occurrence for the first weekday of the current calendar
NSDate *startOfNextWeek = [calendar nextDateAfterDate:[NSDate date] matchingUnit:NSCalendarUnitWeekday value:calendar.firstWeekday options:NSCalendarMatchStrictly];
// Create new date components +7 days and -1 seconds
NSDateComponents *endOfNextWeekComponents = [[NSDateComponents alloc] init];
endOfNextWeekComponents.day = 7;
endOfNextWeekComponents.second = -1;
// Add the date components to the start date to get the end date.
NSDate *endOfNextWeek = [calendar dateByAddingComponents:endOfNextWeekComponents toDate:startOfNextWeek options:NSCalendarMatchStrictly];
NSLog(#"%# - %#", startOfNextWeek, endOfNextWeek);
I'm trying get only the Saturdays and Sundays between two dates, but I don't know why get me free days on a week.
Here is my code:
- (BOOL)checkForWeekend:(NSDate *)aDate {
BOOL isWeekendDate = NO;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSRange weekdayRange = [calendar maximumRangeOfUnit:NSWeekdayCalendarUnit];
NSDateComponents *components = [calendar components:NSWeekdayCalendarUnit fromDate:aDate];
NSUInteger weekdayOfDate = [components weekday];
if (weekdayOfDate == weekdayRange.location || weekdayOfDate == weekdayRange.length) {
// The date falls somewhere on the first or last days of the week.
isWeekendDate = YES;
}
return isWeekendDate;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
NSString *strDateIni = [NSString stringWithString:#"28-01-2012"];
NSString *strDateEnd = [NSString stringWithString:#"31-01-2012"];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"dd-MM-yyyy"];
NSDate *startDate = [df dateFromString:strDateIni];
NSDate *endDate = [df dateFromString:strDateEnd];
unsigned int unitFlags = NSMonthCalendarUnit | NSDayCalendarUnit;
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps = [gregorian components:unitFlags fromDate:startDate toDate:endDate options:0];
// int months = [comps month];
int days = [comps day];
for (int i=0; i<days; i++)
{
NSTimeInterval interval = i;
NSDate * futureDate = [startDate dateByAddingTimeInterval:interval];
BOOL isWeekend = [self checkForWeekend:futureDate]; // Any date can be passed here.
if (isWeekend) {
NSLog(#"Weekend date! Yay!");
}
else
{
NSLog(#"Not is Weekend");
}
}
}
The problem:
The issue was caused by NSTimeInterval interval = i; The logic of the for loop was to iterate by days. Setting the time interval to i was iterating by seconds.
From documentation on NSTimeInterval
NSTimeInterval is always specified in seconds;
The answer:
Changing the NSTimeInterval line to
NSTimeInterval interval = i*24*60*60;
Here is a link to another answer I posted on SO (shameless, I know). It has some code that may help you with dates in the future. The methods are implemented as categories of NSDate, meaning they become methods of NSDate.
There are several functions there that help with weekends. But these two might be most helpful:
- (NSDate*) theFollowingWeekend;
- (NSDate *) thePreviousWeekend;
They return the date of the weekend following and prior to the receiver (self).
Generally, you should not use the notion that a day is 86400 seconds, and should use NSDateComponents and NSCalendar. This works even when daylight savings time transitions occur between dates. Like this:
- (NSDate *) dateByAddingDays:(NSInteger) numberOfDays {
NSDateComponents *dayComponent = [[NSDateComponents alloc] init];
dayComponent.day = numberOfDays;
NSCalendar *theCalendar = [NSCalendar currentCalendar];
return [theCalendar dateByAddingComponents:dayComponent toDate:self options:0];
}
One very important thing to remember is that one day is not (necessarily) equal to 24*60*60 seconds. And you should not do date arithmetic yourself
What you really need to do might seem a little tedious but this is the correct thing to do: use NSCalendar and – dateByAddingComponents:toDate:options:
See Calendrical Calculations guide.
Using today as an example, how do I determine which date it was, 230 workdays ago?
I know how to do it iteratively with a while loop checking date and subtracting 1 if it's a workday, but I'm wondering if there is a better method.
Also, let's take a Sunday 1 PM as an example, and subtract 3 work days and 2 hours from that time. First, it doesn't make sense to subtract work-time from weekends. So it would have to move the time to 23:59:59 of Friday, and then subtract those 3 days and 2 hours.
If it's a Monday at 1:30 AM, and I'm subtracting 5 days and 3 work-hours from that time, then the result should be Friday 22:30 PM of the previous week.
Code to test Kevin's method:
NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *dc = [[NSDateComponents new] autorelease];
dc.month = 12;
dc.day = 19;
dc.year = 2011;
dc.hour = 1;
dc.minute = 0;
dc.second = 0;
NSDate *date = [cal dateFromComponents:dc];
NSLog(#"%#", [date descriptionWithCalendarFormat:nil timeZone:nil locale:nil]);
date = dateBySubtractingWorkOffset(date, 0, 2);
NSLog(#"%#", [date descriptionWithCalendarFormat:nil timeZone:nil locale:nil]);
Output log:
2011-12-02 16:33:46.878 otest[7124:707] 2011-12-19 01:00:00 -0500
2011-12-02 16:33:47.659 otest[7124:707] 2011-12-18 23:00:00 -0500
It should never be 12-18, since that's a Sunday.
Figure out how long from the last weekend your date is, subtract that amount from both your date and your offset. Now you can divide your offset by 5 to figure out how many full weeks are in your offset, and then multiply that by 7 and subtract this new value from your date. Take your previous offset (the one you divided by 5) and mod it by 5, to get the number of remaining days. If it's greater than 0, subtract that offset + 2 (for the weekend) from your date.
Note, this assumes every single weekday is a workday. Corporate holidays tend to make that assumption invalid. If you need to handle holidays, you're in for a much tougher problem.
Update: Here's an attempt to fix David's code to actually express the idea here:
NSDate *dateBySubtractingWorkOffset(NSDate *date, NSUInteger days, NSUInteger hours) {
const int secsInHour = 60*60;
const int secsInDay = 24*secsInHour;
NSTimeInterval offset = days*secsInDay + hours*secsInHour;
NSCalendar *cal = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
// figure out distance from last weekend
{
NSUInteger units = NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSWeekdayCalendarUnit;
NSDateComponents *dc = [cal components:units fromDate:date];
if (dc.weekday == 1 || dc.weekday == 7) {
// we're in the weekend already. Let's just back up until friday
// and then we can start our calculations there
} else {
// figure out our offset from sunday 23:59:59
dc.day -= (dc.weekday - 1);
dc.weekday = 1;
dc.hour = 23;
dc.minute = 23;
dc.second = 23;
NSDate *sunday = [cal dateFromComponents:dc];
NSTimeInterval newOffset = [date timeIntervalSinceDate:sunday];
if (offset < newOffset) {
// our offset doesn't even go back to sunday, we don't need any calculations
return [date dateByAddingTimeInterval:-offset];
}
offset -= [date timeIntervalSinceDate:sunday];
// Now we can jump back to Friday with our new offset
}
// Calculate last friday at 23:59:59
dc.day -= (dc.weekday % 7 + 1);
dc.hour = 23;
dc.minute = 59;
dc.second = 59;
date = [cal dateFromComponents:dc];
}
// We're now set to Friday 23:59:59
// Lets figure out how many weeks we have
int secsInWorkWeek = 5*secsInDay;
NSInteger weeks = (NSInteger)trunc(offset / secsInWorkWeek);
offset -= weeks*secsInWorkWeek;
if (weeks > 0) {
// subtract that many weeks from the date
NSDateComponents *dc = [[NSDateComponents alloc] init];
dc.week = -weeks;
date = [cal dateByAddingComponents:dc toDate:date options:0];
[dc release];
}
// now we can just subtract our remaining offset from the date
return [date dateByAddingTimeInterval:-offset];
}
I haven't exhaustively test this, but it's based on some category methods I use regularly. To determine how many weekdays are between date1 and date2 (assumes date1 < date2), divide the return value of this function by 24*60*60 (the number of seconds in a day).
This splits the calculation into number of days before the first weekend, number of days after the last weekend and number of days in the intervening weeks. A weekend starts on Saturday at 00:00:00 hours and ends on Sunday at 23:59:59 hours. Typically you want to avoid assuming that a day has 24 hours in it, because there may be special cases associated with daylight savings time. So I recommend using NSCalendar to calculate time intervals when this is important. But that happens on weekends, so it is not significant for this case.
There are two methods here. The first returns the NSDate end date if you provide a start date and the number of working days (weekdays) you want to extend out to. (An earlier date is returned if the number of working days is negative.) The second returns the number of seconds that correspond to number of working days (including fractional days) between two given NSDate dates.
I tried to keep calculations within a timezone, but defaulted to the system timezone. (By the way, if you want to calculate with fractional days, change the weekdays parameter to a float. Or you may want to calculate using a parameter in seconds. If so, then also change the calculation of totalInterval in the first method. You won't have to convert to seconds. All subsequent calculations in that method are done in seconds.)
- (NSDate*) calculateWeekDaysEndDateFrom:(NSDate*)_date1 and:(int)weekdays {
NSTimeInterval dayInterval = 24*60*60;
NSTimeInterval totalInterval = dayInterval * (float) weekdays;
NSTimeInterval secondsBeforeWeekend;
NSTimeInterval secondsAfterWeekend;
NSTimeInterval secondsInInterveningWeeks;
int numberOfWeeks;
NSDate *dateOfFirstSaturdayMorning;
NSDate *dateOfLastSundayNight;
NSDate *finalDate;
if (weekdays >0) {
dateOfFirstSaturdayMorning = [_date1 theFollowingWeekend];
secondsBeforeWeekend = [dateOfFirstSaturdayMorning timeIntervalSinceDate:_date1];
numberOfWeeks = (int)((totalInterval - secondsBeforeWeekend)/(5.0 * dayInterval));
secondsInInterveningWeeks = 5 * (float)(numberOfWeeks * dayInterval);
secondsAfterWeekend = totalInterval - secondsBeforeWeekend - secondsInInterveningWeeks;
dateOfLastSundayNight = [[dateOfFirstSaturdayMorning dateByAddingDays:7*numberOfWeeks+2] dateByAddingTimeInterval:-1]; // move from saturday morning to monday morning, then back off 1 second
finalDate = [dateOfLastSundayNight dateByAddingTimeInterval:secondsAfterWeekend];
}
else {
dateOfLastSundayNight = [_date1 thePreviousWeekend];
secondsAfterWeekend = [date1 timeIntervalSinceDate:dateOfLastSundayNight];
numberOfWeeks = (int)((-totalInterval - secondsAfterWeekend)/(5.0 * dayInterval));
secondsInInterveningWeeks = 5 * (float)(numberOfWeeks * dayInterval);
dateOfFirstSaturdayMorning = [[dateOfLastSundayNight dateByAddingDays:-(7*numberOfWeeks+2)] dateByAddingTimeInterval:+1];
secondsBeforeWeekend = -totalInterval - secondsInInterveningWeeks - secondsAfterWeekend;
finalDate = [dateOfFirstSaturdayMorning dateByAddingTimeInterval:-secondsBeforeWeekend];
}
NSLog(#"dateOfFirstSaturdayMorning = %#", [dateOfFirstSaturdayMorning descriptionWithLocale:[NSLocale currentLocale]]);
NSLog(#"dateOfLastSundayNight = %#",[dateOfLastSundayNight descriptionWithLocale:[NSLocale currentLocale]]);
NSLog(#"date 1 = %#", date1);
NSLog (#"daysBeforeWeekend = %.2f", secondsBeforeWeekend/((float)dayInterval));
NSLog (#"daysBetweenWeekends = %.2f", secondsInInterveningWeeks/((float)(dayInterval)));
NSLog (#"daysAfterWeekend = %.2f", secondsAfterWeekend/((float)dayInterval));
NSLog (#"numberOfWeekdays = %.2f", (secondsBeforeWeekend + secondsInInterveningWeeks + secondsAfterWeekend)/((float)dayInterval));
NSLog(#"endDateFromWeekdays = %#", [finalDate descriptionWithLocale:[NSLocale currentLocale]]);
return finalDate;
}
- (NSTimeInterval) calculateWeekdaysFrom:(NSDate*)_date1 and:(NSDate*)_date2 {
if (_date1 && _date2) {
NSTimeInterval secondsBeforeWeekend;
NSTimeInterval secondsAfterWeekend;
NSDate *dateOfFirstSaturdayMorning;
NSDate *dateOfLastSundayNight;
NSTimeInterval dayInterval = 24*60*60; // This isn't always true, e.g., if daylight savings intervenes. (But that happens on the weekend in most places.)
// see if they are in the same week
if (([_date1 ordinality] < [_date2 ordinality]) && [_date2 timeIntervalSinceDate:_date1] <= 5*dayInterval) {
return [_date2 timeIntervalSinceDate:_date1];
}
// time interval before a first weekend
if ([_date1 ordinality] == 1 || [_date1 ordinality] == 7) {
secondsBeforeWeekend = 0;
dateOfFirstSaturdayMorning = _date1; // This is just a convenience. It's not true. But, later, rounding takes place to deal with it.
}
else {
dateOfFirstSaturdayMorning = [_date1 theFollowingWeekend];
secondsBeforeWeekend = [dateOfFirstSaturdayMorning timeIntervalSinceDate:_date1];
}
int ordDate2 = [_date2 ordinality];
int ordFirstSaturday = [dateOfFirstSaturdayMorning ordinality];
// time interval after a last weekend
if ([_date2 ordinality] == 1 || [_date2 ordinality] == 7) {
secondsAfterWeekend = 0;
dateOfLastSundayNight = _date2; // Again, this is just a convenience. It's not true.
}
else {
dateOfLastSundayNight = [_date2 thePreviousWeekend];
secondsAfterWeekend = [_date2 timeIntervalSinceDate:dateOfLastSundayNight];
}
NSTimeInterval intervalBetweenWeekends = [dateOfLastSundayNight timeIntervalSinceDate:dateOfFirstSaturdayMorning];
int numberOfWeeks = (int) (intervalBetweenWeekends/(7*dayInterval));
int secondsInInterveningWeeks = (float) (5*dayInterval*numberOfWeeks);
NSLog(#"date 1 = %#", [_date1 descriptionWithLocale:[NSLocale currentLocale]]);
NSLog(#"date 2 = %#", [_date2 descriptionWithLocale:[NSLocale currentLocale]]);
NSLog(#"dateOfFirstSaturdayMorning = %#", [dateOfFirstSaturdayMorning descriptionWithLocale:[NSLocale currentLocale]]);
NSLog(#"dateOfLastSundayNight = %#",[dateOfLastSundayNight descriptionWithLocale:[NSLocale currentLocale]]);
NSLog (#"daysBeforeWeekend = %.2f", secondsBeforeWeekend/((float)dayInterval));
NSLog (#"daysBetweenWeekends = %.2f", secondsInInterveningWeeks/((float)(dayInterval)));
NSLog (#"daysAfterWeekend = %.2f", secondsAfterWeekend/((float)dayInterval));
NSLog (#"numberOfWeekdays = %.2f", (secondsBeforeWeekend + secondsInInterveningWeeks + secondsAfterWeekend)/((float)dayInterval));
return secondsBeforeWeekend + secondsInInterveningWeeks + secondsAfterWeekend;
}
else
return 0;
}
The files for category methods on NSDate are NSDate+help.h
#interface NSDate (help)
+ (NSDate *) LSExtendedDateWithNaturalLanguageString:(NSString *)dateString WithFormatter:(NSDateFormatter*)dateFormatter;
- (NSUInteger)ordinality;
- (NSDate*) theFollowingWeekend;
- (NSDate *) thePreviousWeekend;
- (NSDate *) dateByAddingDays:(NSInteger) numberOfDays;
- (NSDate *) dateByMovingToBeginningOfDayInTimeZone:(NSTimeZone*)tz;
- (NSDate *) dateByMovingToEndOfDayInTimeZone:(NSTimeZone*)tz;
#end
and NSDate+help.m
#import "NSDate+help.h"
#implementation NSDate (help)
// thrown in for testing
+ (NSDate *) LSExtendedDateWithNaturalLanguageString:(NSString *)dateString WithFormatter:(NSDateFormatter*)dateFormatter{
[dateFormatter setDateFormat:#"yyyy-MM-dd HHmm"];
[dateFormatter setLocale:[NSLocale currentLocale]];
//NSDate *formattedDate = [dateFormatter dateFromString:#"2008-12-3T22-11-30-123"];
return [dateFormatter dateFromString:dateString];
}
- (NSUInteger)ordinality {
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone systemTimeZone]];
return [calendar ordinalityOfUnit:NSDayCalendarUnit inUnit:NSWeekCalendarUnit forDate:self];
}
- (NSDate*) theFollowingWeekend {
NSUInteger myOrdinality = [self ordinality];
NSDate *dateOfFollowingWeekend = [self dateByAddingDays:(7-myOrdinality)%7];
return [dateOfFollowingWeekend dateByMovingToBeginningOfDayInTimeZone:(NSTimeZone*)nil];
}
- (NSDate *) thePreviousWeekend {
NSUInteger myOrdinality = [self ordinality];
NSDate *dateOfPreviousWeekend = [self dateByAddingDays:(1-myOrdinality)];
return [dateOfPreviousWeekend dateByMovingToEndOfDayInTimeZone:(NSTimeZone*)nil];
}
- (NSDate *) dateByAddingDays:(NSInteger) numberOfDays {
NSDateComponents *dayComponent = [[NSDateComponents alloc] init];
dayComponent.day = numberOfDays;
NSCalendar *theCalendar = [NSCalendar currentCalendar];
return [theCalendar dateByAddingComponents:dayComponent toDate:self options:0];
}
- (NSDate *) dateByMovingToBeginningOfDayInTimeZone:(NSTimeZone*)tz {
NSTimeZone *timezone;
if (tz)
timezone = tz;
else
timezone = [NSTimeZone systemTimeZone];
unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents* parts = [[NSCalendar currentCalendar] components:flags fromDate:self];
[parts setHour:0];
[parts setMinute:0];
[parts setSecond:0];
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:timezone];
return [calendar dateFromComponents:parts];
}
- (NSDate *)dateByMovingToEndOfDayInTimeZone:(NSTimeZone*)tz {
NSTimeZone *timezone;
if (tz)
timezone = tz;
else
timezone = [NSTimeZone systemTimeZone];
unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents* parts = [[NSCalendar currentCalendar] components:flags fromDate:self];
[parts setHour:23];
[parts setMinute:59];
[parts setSecond:59];
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:timezone];
return [calendar dateFromComponents:parts];
}
#end
The category method ordinality returns the number for the day of the week of the receiver. Sunday = 1, Saturday = 7. This is used to find out how many days there are before the end of the first week and how many days there are after the beginning the last week. (Calculations are actually carried out in seconds.)
The category methods theFollowingWeekend and thePreviousWeekend return the NSDate at midnight on the Saturday morning that follows the receiver date and the NSDate one second before midnight on the Sunday that follows the receiver date. These methods assume you have already validated that the receiver date is not on the weekend. I handled that in the main methods. Look for the checks of ordinality == 1 or 7.
dateByMovingToBeginningOfDayInTimeZone: and dateByMovingToEndOfDayInTimeZone: set the hours, minutes, and seconds of the receiver date to 00:00:00 and 23:59:59 respectively. This is for delimiting weekends, which run from midnight Saturday morning to midnight Sunday night in the timezone.
Hope this helps. This was an exercise for me to become more familiar with the time and date functionality.
I'll credit Keith Lazuka and his calendar component for iPhone for the germination of this code.
Here's a screen shot of a test program user interface that uses these functions:
Here is your example, run through the first method. The items of interest are highlighted.
. For this, I made the simple modification to accept fractional days (which i mentioned above, but did not include in the code shown above)
Using info from above I have made a simple method to work out weekdays between two dates. Could not find this anywhere so I thought I'd post.
- (NSInteger)endDate:(NSDate *)eDate minusStartDate:(NSDate *)sDate{
int weekDaysCount;
weekDaysCount = 0;
//A method that calculates how many weekdays between two dates
//firstcompare dates to make sure end date is not in the past
//using the NScomparisonresult and the NSDate compare: method
NSComparisonResult result = [sDate compare:eDate];
if (result == NSOrderedDescending) {
eDate = sDate;
//NSLog(#"invalid date so set to end date to start date");
}
//Work out the number of days btween the twodates passed in
//first set up a gregorian calander
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSUInteger unitFlags = NSDayCalendarUnit;
NSDateComponents *components = [gregorian components:unitFlags
fromDate:sDate
toDate:eDate options:0];
//get the number of days
NSInteger days = [components day];
//now loop through the days and only count the weekdays
while (days > 0) {//while days are greater than 0
// NSLog(#"days = %i", days);
//get the weekday number of the start date
NSDateComponents *comps = [gregorian components:NSWeekdayCalendarUnit fromDate:sDate];
// NSLog(#"sDate %#", sDate);
int weekday = [comps weekday];
// NSLog(#"Comps Weekday = %i", weekday);
//Test for a weekday - if its not a Saturday or Sunday
if ((weekday!=7) && (weekday !=1)){
//increase weekDays count
weekDaysCount ++;
// NSLog(#"weekDaysCount is %i", weekDaysCount);
// NSLog(#"-------------------------");
}
//decrement the days
days -=1;
//increase the date so the next day can be tested
sDate = [sDate dateByAddingTimeInterval:(60 * 60 * 24)];
}
return weekDaysCount;
}
I want to compare two dates: date1 and date2
2011-06-06 12:59:48.994 Project[419:707] firstDate:2011-06-06 10:59:21 +0000
2011-06-06 12:59:49.004 Project[419:707] selectedData:2011-06-06 10:59:17 +0000
but these dates have different time and when I use NSOrderedSame it don't work fine, how can I solve?
my code:
NSDate *firstDate = [[appDelegate.project objectAtIndex:i]objectAtIndex:3];
NSDate *secondDate = [[appDelegate.project objectAtIndex:i]objectAtIndex:4];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger comps = (NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit);
NSDateComponents *date1Components = [calendar components:comps
fromDate:firstDate];
NSDateComponents *date2Components = [calendar components:comps
fromDate:secondDate];
NSDateComponents *date3Components = [calendar components:comps fromDate:appDelegate.selectedDate];
NSLog(#"firstDate:%#", [date1Components date]);
NSLog(#"secondDate:%#", [date2Components date]);
NSLog(#"selectedData:%#", [date3Components date]);
NSComparisonResult compareStart = [[date1Components date] compare: [date3Components date]];
NSComparisonResult compareEnd = [[date2Components date] compare: [date3Components date]];
if ((compareStart == NSOrderedAscending || compareStart == NSOrderedSame)
&& (compareEnd == NSOrderedDescending || compareEnd == NSOrderedSame))
{
NSLog(#"inside");
Then I want to compare my dates and entry inside the "if" when date1 <= selectedDate <= date2; now I understand because I have a warning: I should add this "[date1Components date]" and it work; the problem is that I have in the NSLog null values, why??
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger comps = (NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear);
NSDateComponents *date1Components = [calendar components:comps
fromDate: date1];
NSDateComponents *date2Components = [calendar components:comps
fromDate: date2];
date1 = [calendar dateFromComponents:date1Components];
date2 = [calendar dateFromComponents:date2Components];
NSComparisonResult result = [date1 compare:date2];
if (result == NSOrderedAscending) {
} else if (result == NSOrderedDescending) {
} else {
//the same
}
There is another handy method to create for a given date the date that represents the start of a given unit: [aCalendar rangeOfUnit:startDate:interval:forDate:]
To illustrate how this method works, see this code, that easily creates the date for the beginning of the day, week, month and year for a given date (here: now).
NSDate *now = [NSDate date];
NSDate *startOfToday = nil;
NSDate *startOfThisWeek = nil;
NSDate *startOfThisMonth = nil;
NSDate *startOfThisYear = nil;
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&startOfToday interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSWeekCalendarUnit startDate:&startOfThisWeek interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSMonthCalendarUnit startDate:&startOfThisMonth interval:NULL forDate:now];
[[NSCalendar currentCalendar] rangeOfUnit:NSYearCalendarUnit startDate:&startOfThisYear interval:NULL forDate:now];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateStyle:NSDateFormatterFullStyle];
[formatter setTimeStyle:NSDateFormatterFullStyle];
NSLog(#"%#", [formatter stringFromDate:now]);
NSLog(#"%#", [formatter stringFromDate:startOfToday]);
NSLog(#"%#", [formatter stringFromDate:startOfThisWeek]);
NSLog(#"%#", [formatter stringFromDate:startOfThisMonth]);
NSLog(#"%#", [formatter stringFromDate:startOfThisYear]);
result:
Thursday, July 12, 2012, 4:36:07 PM Central European Summer Time
Thursday, July 12, 2012, 12:00:00 AM Central European Summer Time
Sunday, July 8, 2012, 12:00:00 AM Central European Summer Time
Sunday, July 1, 2012, 12:00:00 AM Central European Summer Time
Sunday, January 1, 2012, 12:00:00 AM Central European Standard Time
this allows us to shorten the first code to:
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&date1 interval:NULL forDate:date1];
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&date2 interval:NULL forDate:date2];
NSComparisonResult result = [date1 compare:date2];
if (result == NSOrderedAscending) {
} else if (result == NSOrderedDescending) {
} else {
//the same
}
Note, that in this code, date1 and date2 will be overwritten. Alternatively you can pass in a reference to another NSDate pointer for startDate as shown in the code above, where now stays untouched.
I have used another method with NSDateFormatter and a string comparison, less smarter than
NSDate compare method but faster to write and flexible enough to do variety of comparison :
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd"];
if ([[dateFormat stringFromDate:date1] isEqualToString:[dateFormat stringFromDate:date2]])
{
//It's the same day
}
Okay, so it's a few years after the original question was asked, but it's probably worth mentioning that NSCalendar now has a number of methods that make certain date comparison questions much more straight-forward:
NSCalendar *currentCalendar = [NSCalendar currentCalendar];
Bool sameDay = [currentCalendar isDate:dateA inSameDayAsDate:dateB];
Swift Version , Comparing Dates and ignoring their time.
let dateExam1:NSDate = NSDate.init(timeIntervalSinceNow: 300)
let dateExam2:NSDate = NSDate.init(timeIntervalSinceNow: 10000)
let currCalendar = NSCalendar.currentCalendar()
let dateCompanent1:NSDateComponents = currCalendar.components([.Year,.Month,.Day], fromDate: dateExam1)
let dateCompanent2:NSDateComponents = currCalendar.components([.Year,.Month,.Day], fromDate: dateExam2)
let date1WithoutTime:NSDate? = currCalendar .dateFromComponents(dateCompanent1)
let date2WithoutTime:NSDate? = currCalendar .dateFromComponents(dateCompanent2)
if (date1WithoutTime != nil) && (date2WithoutTime != nil)
{
let dateCompResult:NSComparisonResult = date1WithoutTime!.compare(date2WithoutTime!)
if (dateCompResult == NSComparisonResult.OrderedSame)
{
print("Same Dates")
}
else
{
print("Different Dates")
}
}
Updating #LuAndre answer swift 5
let dateExam1 = Date(timeIntervalSinceNow: 300)
let dateExam2 = Date(timeIntervalSinceNow: 10000)
let currCalendar = Calendar.current
let dateCompanent1 = currCalendar.dateComponents([.year,.month,.day], from: dateExam1)
let dateCompanent2 = currCalendar.dateComponents([.year,.month,.day], from: dateExam2)
if let date1WithoutTime = currCalendar.date(from:dateCompanent1), let dateCompanent2 = currCalendar.date(from:dateCompanent2) {
let dateCompResult = date1WithoutTime.compare(dateCompanent2)
if (dateCompResult == ComparisonResult.orderedSame)
{
print("Same Dates")
}
else
{
print("Different Dates")
}
}
I have this category added to NSDate:
- (bool)isWeekend
{
NSString* s = [self asString:#"e"];
if ([s isEqual:#"6"])
return YES;
else if ([s isEqual:#"7"])
return YES;
else
return NO;
}
Helper function:
- (NSString*)asString:(NSString*)format
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:format];
NSString *formattedDateString = [dateFormatter stringFromDate:self];
[dateFormatter release];
return formattedDateString;
}
isWeekend should return YES if it is a saturday or a sunday. But it does not work if the locale has a week start on a sunday, in which case friday will be day 6 and saturday will be day 7.
How can I solve this?
You want to use NSCalendar and NSDateComponents:
NSDate *aDate = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSRange weekdayRange = [calendar maximumRangeOfUnit:NSWeekdayCalendarUnit];
NSDateComponents *components = [calendar components:NSWeekdayCalendarUnit fromDate:aDate];
NSUInteger weekdayOfDate = [components weekday];
if (weekdayOfDate == weekdayRange.location || weekdayOfDate == weekdayRange.length) {
//the date falls somewhere on the first or last days of the week
NSLog(#"weekend!");
}
This is operating under the assumption that the first and last days of the week comprise the "week ends" (which is true for the Gregorian calendar. It may not be true in other calendars).
As of iOS 8, you can use isDateOnWeekend: on NSCalendar.
In Swift 3+:
extension Date {
var isWeekend: Bool {
return NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!.isDateInWeekend(self)
}
}
In Swift:
func isWeekend(date: NSDate) -> Bool {
let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
return calendar.isDateInWeekend(date)
}