How many quarters between two dates? - objective-c

NSCalendar *calendar= [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSCalendarUnit unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *dateStart = [calendar components:unitFlags fromDate:start];
quarterStart = [dateStart quarter];
NSDateComponents *dateEnd = [calendar components:unitFlags fromDate:end];
quarterEnd = [dateEnd quarter];
Having two NSDate start and end and extracting start quarter and end quarter i need to know the differences in quarters between these 2 dates.
I know that i could divide the total days / 90 days but i'm looking at another solution having only these data.
Any hints ?

You should try:
NSDateComponents *result = [[NSCalendar currentCalendar] components:NSQuarterCalendarUnit fromDate:start toDate:end options:0];
NSInteger numberOfQuaters = [result quarter];

I've solved using that, cause the other suggested answer not works for an Apple's bug on quarter Unit.
numberOfQuarters = (4 - startQuarter) + ((endYear -1 - startYear) * 4) + endQuarter;

Related

Extract week of year with components / set Monday as first weekday

I am developing an application, in which I repeatedly have to calculate in which week of the year a certain date is.
I know it sounds very simple. I would just use a date formatter if Sunday was not rated as next week, which annoys me.
So I decided to use date components. I have modified the calendar object, so the first weekday is Monday:
+ (NSInteger) getNumberOfWeekOfYearFromDate:(NSDate *)entryDate{
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setFirstWeekday: 2];
NSDateComponents *components = [calendar components:NSWeekCalendarUnit | NSYearForWeekOfYearCalendarUnit | NSYearCalendarUnit fromDate:entryDate];
NSInteger weekOfYear = [components weekOfYear];
return weekOfYear;
}
Unfortunately the return values are large numbers like "2147483647". What am I doing wrong? I did not find any solution when I was searching the web.
Cheers and thanks in advance
Try this:
+ (NSInteger) getNumberOfWeekOfYearFromDate:(NSDate *)entryDate{
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setFirstWeekday: 2];
NSDateComponents *components = [calendar components:
NSCalendarUnitWeekOfYear | NSCalendarUnitYear fromDate:entryDate];
NSInteger weekOfYear = [components weekOfYear];
return weekOfYear;
}

Get the Week Number in iOS SDK

I want to get the Week number of the year from the date.I tried the code as follow but gives me a wrong week number.
My code for week number:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"YYYY-MM-dd"];
NSDate *date = [dateFormatter dateFromString:#"2012-09-15"];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSLog(#"week: %i", [[calendar components: NSWeekOfYearCalendarUnit fromDate:date] weekOfYear]); //Display 38 instead of 37
}
Note: If i try with with [NSDate date] display the correct.
Help me to solve this..
Thank you,
ObjectiveC:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComponent = [calendar components:(NSWeekOfYearCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit) fromDate:[NSDate date]];
NSLog(#"%#",dateComponent);
Update
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComponent = [calendar components:(NSCalendarUnitWeekOfYear | NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear) fromDate:date];
NSLog(#"%#",dateComponent);
Swift:
let calendar = NSCalendar.currentCalendar()
let dateComponent = calendar.components([.WeekOfYear, .Day, .Month, .Year], fromDate: NSDate(timeIntervalSinceNow: 0))
print("weekOfYear \(dateComponent.weekOfYear)")
Swift 3 - Swift 5:
let component = Calendar.current.component(.weekOfYear, from: Date())
print("Week of Year \(component)")
[NSCalendar currentCalendar] gives you a Gregorian Calendar as default. You can use
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSISO8601Calendar];
to get an ISO 08601 conform calendar, which has week number 37 for your date.
Swift 3:
You need know last Date of selected month. Than check number of week for this week, and this will be your number of weeks in month
return Calendar.current.component(.weekOfMonth, from: lastDate ?? Date())
Updated code in ObjectiveC used Xcode version - 9.1 - :
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *dateComponent = [calendar components:(NSCalendarUnitWeekOfYear | NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear) fromDate:[NSDate date]];
NSLog(#"%ld",(long)[dateComponent weekOfYear]);

Number of Months and Days between two NSDates

I would like to calculate the number of months and days between two NSDates. I have the number of days calculating correctly, but how can convert that to months and remainder days?
This is what I'm using to calculate total number of days, which is working correctly.
- (NSInteger) numberOfDaysUntil {
NSDate *fromDate;
NSDate *toDate;
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&fromDate interval:NULL forDate:[self dateOnly:[NSDate date]]];
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&toDate interval:NULL forDate:[self dateOnly:self]];
NSDateComponents *difference = [calendar components:NSDayCalendarUnit fromDate:fromDate toDate:toDate options:0];
return [difference day];
}
As Hot Licks correctly said, you can't convert a number of days to months/days in most calendars.
However, the NSCalendar method components:fromDate:toDate:options: can do this calculation if you agree with Apple's implementation. From the documentation:
The result is lossy if there is not a small enough unit requested to hold the full precision of the difference. Some operations can be ambiguous, and the behavior of the computation is calendar-specific, but generally larger components will be computed before smaller components; for example, in the Gregorian calendar a result might be 1 month and 5 days instead of, for example, 0 months and 35 days.
The discussion in the documentation even includes sample code for exactly your problem:
NSDate *startDate = ...;
NSDate *endDate = ...;
unsigned int unitFlags = NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *comps = [gregorian components:unitFlags fromDate:startDate toDate:endDate options:0];
int months = [comps month];
int days = [comps day];

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];
}

2 NSDateComponents - is it same week?

i have got a function with BOOL return value and 2 input (NSDateComponents *) parameters.
My trouble is I have two NSDateComponents values and I want to know if the two date fall within the same calendar week. i tried the simplest solutions to solve problem, my idea was the following:
- (BOOL)isFunctionName:(NSDateComponents *)comp1 andParam:(NSDateComponents *)comp2 {
return (([comp1 week] == [comp2 week]) && ([comp1 year] == [comp2 year]));
}
but it's not correct.
what way i can solve it ?
edited
so i have a function which makes datecomponents from dates.
-(NSDateComponents *)dateToDateComponents:(NSDate *)date {
unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [gregorian components:unitFlags fromDate:date];
[gregorian release];
return dateComponents;
}
and i call it this way:
if ([self isFunctionName: [self dateToDateComponents:startDate] and Param:[self dateToDateComponents:currentTripDate]]){
}
and during my test it returns YES all of my dates (for example 2010.07.21 - 2010.08.18)
This is inspired by Robert's answer. I tweaked it a bit to address the issue when a week crosses two years, e.g. 12/31/2012 & 1/1/2013.
- (BOOL)isOnSameWeekAsDate:(NSDate*)otherDate
{
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
unsigned unitFlags = NSCalendarUnitYearForWeekOfYear | NSCalendarUnitWeekOfYear;
NSDateComponents *components = [calendar components:unitFlags fromDate:self];
NSDateComponents *otherComponents = [calendar components:unitFlags fromDate:otherDate];
return ( [components yearForWeekOfYear] == [otherComponents yearForWeekOfYear] && [components weekOfYear] == [otherComponents weekOfYear] );
}
The NSDateComponent class reference states:
Important: An NSDateComponents object is meaningless in itself; you
need to know what calendar it is
interpreted against, and you need to
know whether the values are absolute
values of the units, or quantities of
the units.
What about comparing NSDates instead?
- (BOOL) weekIsEqual:(NSDate *)date and:(NSDate *)otherDate {
NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDateComponents *dateComponents = [gregorian components:NSWeekdayCalendarUnit | NSYearCalendarUnit fromDate:date];
NSDateComponents *otherDateComponents = [gregorian components:NSWeekdayCalendarUnit | NSYearCalendarUnit fromDate:otherDate];
return [dateComponents week] == [otherDateComponents week] && [dateComponents year] == [otherDateComponents year];
}
edit:
In this line:
unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
You don't pass NSWeekCalendarUnit, therefore [dateComponent week] returns NSUndefinedDateComponent
edit
Of course, it has to be NSWeekCalendarUnit…
Starting from iOS8, this became much easier:
-(BOOL)isDate:(NSDate *)date1 onSameWeekAs:(NSDate *)date2
{
return [[NSCalendar currentCalendar] isDate:date1
equalToDate:date2
toUnitGranularity:NSCalendarUnitWeekOfYear];
}
From the documentation:
returns YES if both dates have equal date component for all units
greater than or equal to the given unit, otherwise NO.