I want to get list of days in selected month.
For example, If user select feb then it show 1 to 28 0r 29 days. How can i do that?
Thanks
You can try the following code, I have given the today's date to find the list of dates in this month. You can give some other date to find the list of that given month.
NSDate *today = [NSDate date];
NSCalendar *cal = [NSCalendar currentCalendar];
NSMutableArray *datesThisMonth = [NSMutableArray array];
NSRange rangeOfDaysThisMonth = [cal rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:today];
NSDateComponents *components = [cal components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSEraCalendarUnit) fromDate:today];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
for (NSInteger i = rangeOfDaysThisMonth.location; i < NSMaxRange(rangeOfDaysThisMonth); ++i) {
[components setDay:i];
NSDate *dayInMonth = [cal dateFromComponents:components];
[datesThisMonth addObject:dayInMonth];
}
NSLog(#"datesThisMonth: %#", datesThisMonth);
You can retrieve the number of days in specified month
NSCalendar* cal = [NSCalendar currentCalendar];
NSDateComponents* comps = [[NSDateComponents alloc] init];
// Set month here
[comps setMonth:2]; // 2 = February
NSRange range = [cal rangeOfUnit:NSDayCalendarUnit
inUnit:NSMonthCalendarUnit
forDate:[cal dateFromComponents:comps]];
NSLog(#"current day count in this month: %lu", (unsigned long)range.length);
I have an open source calendar event project. Maybe you can check it out if you need anything.
DPCalendar
I have simplied it to
- (NSInterger) numberOfDaysForMonth:(NSDate *)date {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate: date];
[components setDay:1];
//Get the first day of the month
NSDate *firstDay = [calendar dateFromComponents:components];
[components setDay:0];
[components setMonth:components.month + 1];
//Get the last day of the month
NSDate *lastDay = [calendar dateFromComponents:components];
components = [self.calendar components:NSDayCalendarUnit fromDate:firstDay toDate:lastDay options:0];
return components.day + 1;
}
Cheers
Generally, we only need to handle Feb depend on the year, here's my method implemented:
+ (NSUInteger)numberOfDaysForYear:(NSInteger)year
month:(NSInteger)month
{
if (2 == month) {
NSCalendar * gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents * dateComponents = [[NSDateComponents alloc] init];
[dateComponents setYear:year];
[dateComponents setMonth:month];
[dateComponents setDay:1];
NSDate * firstDayDate = [gregorianCalendar dateFromComponents:dateComponents];
NSRange days = [gregorianCalendar rangeOfUnit:NSCalendarUnitDay
inUnit:NSCalendarUnitMonth
forDate:firstDayDate];
return days.length;
} else if (4 == month || 6 == month || 9 == month || 11 == month) {
return 30;
} else {
return 31;
}
}
Related
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.
I am using NSDateComponents and NSCalendar to get the dates between two dates.
// Get dates between before and after
NSDateComponents *betweenDateComponents = [calendar components:componentFlags
fromDate:afterDate
toDate:beforeDate
options:0];
I then have a simple for loop that is based on the components' day property:
for (int i = 1; i < betweenDateComponents.day; ++i) {
This works perfectly when I am working with all of the days for a week, or a month. If I filter by week, the day property logs as 6. If I filter by month the day property is 29, but for some reason when I filter by year, the day property logs as 29 instead of 364.
Why is the day property always wrong when I'm trying to work with a year?
Here is all of my code up until the for loop I included above:
// Set the date components according to the type of filter we're doing
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [NSDateComponents new];
if (filterType == CommentFilterTypeWeeklyByDay) {
[components setDay:-6];
} else if (filterType == CommentFilterTypeMonthlyByDay) {
[components setDay:-29];
} else if (filterType == CommentFilterTypeYearlyByMonth) {
[components setDay:-364];
}
NSUInteger componentFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
// Zero out before and after dates
NSDate *beforeDate = [NSDate date];
NSDateComponents *zeroComponents = [[NSCalendar currentCalendar] components:componentFlags fromDate:beforeDate];
beforeDate = [calendar dateFromComponents:zeroComponents];
NSDate *afterDate = [calendar dateByAddingComponents:components toDate:beforeDate options:0];
zeroComponents = [[NSCalendar currentCalendar] components:componentFlags fromDate:afterDate];
afterDate = [calendar dateFromComponents:zeroComponents];
NSMutableArray *dates = [NSMutableArray new];
[dates addObject:afterDate];
// Get dates between before and after
NSDateComponents *betweenDateComponents = [calendar components:componentFlags
fromDate:afterDate
toDate:beforeDate
options:0];
NSLog(#"%d", betweenDateComponents.day);
for (int i = 1; i < betweenDateComponents.day; ++i) {
Because your components include NSYearCalendarUnit and NSMonthCalendarUnit, I suspect you'll have to use month and year instead of just day. The components are cumulative, not independent.
You will always be able to get just the number of days (regardless of how many months or years are between your dates) by changing your components:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [NSDateComponents new];
switch (filterType) {
case CommentFilterTypeWeeklyByDay: [components setDay:-6]; break;
case CommentFilterTypeMonthlyByDay: [components setDay:-29]; break;
case CommentFilterTypeYearlyByMonth: [components setDay:-364]; break;
case CommentFilterTypeCustom: [components setDay:-590]; break;
default: break;
}
NSUInteger componentFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDate *beforeDate = [NSDate date];
NSDateComponents *zeroComponents = [[NSCalendar currentCalendar] components:componentFlags fromDate:beforeDate];
beforeDate = [calendar dateFromComponents:zeroComponents];
NSDate *afterDate = [calendar dateByAddingComponents:components toDate:beforeDate options:0];
zeroComponents = [[NSCalendar currentCalendar] components:componentFlags fromDate:afterDate];
afterDate = [calendar dateFromComponents:zeroComponents];
NSDateComponents *betweenDateComponents = [calendar components:NSDayCalendarUnit
fromDate:afterDate
toDate:beforeDate
options:0];
NSLog(#"%d", betweenDateComponents.day);
The NSLog here prints
6 for CommentFilterTypeWeeklyByDay
29 for CommentFilterTypeMonthlyByDay
364 for CommentFilterTypeYearlyByMonth
590 for CommentFilterTypeCustom
I know there are some questions similar to this one, but I just can't find what's wrong with my code.
Basically what I want is if today is not sunday, currentDate is set to the last sunday.
If today is sunday I currentDate is set to the sunday before.
Here's how I'm trying to do it.
NSDateComponents *components = [[NSCalendar currentCalendar] components: NSWeekCalendarUnit | NSYearCalendarUnit | NSWeekdayCalendarUnit fromDate:currentDate];
if (components.weekday == 1) { //Its sunday. We just need to subtract a week
[components setWeek: -1];
currentDate = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:currentDate options:0];
}else{ //If its not sunday we just go to sunday
[components setWeekday: 1];
currentDate = [[NSCalendar currentCalendar] dateFromComponents:components];
}
The first time this part of the code is executed I get the right answer. After the first time I get weird dates, like 02 Dec. 4026, and the year keeps going up.
Here's the code that made it work:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components: ( NSWeekCalendarUnit | NSWeekdayCalendarUnit | NSYearCalendarUnit) fromDate:currentDate];
int weekday = components.weekday;
if (weekday == 1) {
[components setWeek:components.week -1];
}else{
[components setWeekday:1];
}
currentDate = [calendar dateFromComponents:components];
Use nextDateAfterDate with the .SearchBackwards option if you are using iOS 8.0+
let calendar = NSCalendar.currentCalendar()
let options: NSCalendarOptions = [.MatchPreviousTimePreservingSmallerUnits, .SearchBackwards]
calendar.nextDateAfterDate(NSDate(), matchingUnit: .Weekday, value: 1, options: options)
Try this category on NSCalendar
#interface NSCalendar (LastSunday)
-(NSDate *)previousSundayForDate:(NSDate *)date;
#end
#implementation NSCalendar (LastSunday)
-(NSDate *)previousSundayForDate:(NSDate *)date
{
static NSUInteger SUNDAY = 1;
static NSUInteger MONDAY = 2;
NSDate *startOfWeek;
[self rangeOfUnit:NSWeekCalendarUnit
startDate:&startOfWeek
interval:NULL
forDate:date];
if(self.firstWeekday == SUNDAY){
NSDate *beginningOfDate;
[self rangeOfUnit:NSDayCalendarUnit
startDate:&beginningOfDate
interval:NULL forDate:date];
if ([startOfWeek isEqualToDate:beginningOfDate]) {
startOfWeek = [self dateByAddingComponents:(
{
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.day = -7;
comps;
})
toDate:startOfWeek
options:0];
}
return startOfWeek;
}
if(self.firstWeekday == MONDAY)
return [self dateByAddingComponents:(
{
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.day = -1;
comps;
})
toDate:startOfWeek
options:0];
return nil;
}
#end
use it as:
NSDate *lastSunday = [calendar previousSundayForDate:[NSDate date]];
PS:
a version for "one-method-one-return-statement"- fetishists:
#implementation NSCalendar (LastSunday)
-(NSDate *)previousSundayForDate:(NSDate *)date
{
NSDate *resultDate = nil;
static NSUInteger SUNDAY = 1;
static NSUInteger MONDAY = 2;
NSDate *startOfWeek;
[self rangeOfUnit:NSWeekCalendarUnit
startDate:&startOfWeek
interval:NULL
forDate:date];
if(self.firstWeekday == SUNDAY){
NSDate *beginningOfDate;
[self rangeOfUnit:NSDayCalendarUnit
startDate:&beginningOfDate
interval:NULL forDate:date];
if ([startOfWeek isEqualToDate:beginningOfDate]) {
startOfWeek = [self dateByAddingComponents:(
{
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.day = -7;
comps;
})
toDate:startOfWeek
options:0];
}
resultDate = startOfWeek;
}
if(self.firstWeekday == MONDAY)
resultDate = [self dateByAddingComponents:(
{
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.day = -1;
comps;
})
toDate:startOfWeek
options:0];
return resultDate;
}
#end
The reason you got 4026 is because of this line:
NSDateComponents *components = [[NSCalendar currentCalendar] components: NSWeekCalendarUnit | NSYearCalendarUnit | NSWeekdayCalendarUnit fromDate:currentDate];
It sets the year component to the current year, 2013. It also initializes the week and weekday components. Then the components are added to the current date, which doubles the year to 4026, here:
[components setWeek: -1];
currentDate = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:currentDate options:0];
If you want to subtract only one week, do it like this:
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setWeek: -1];
currentDate = [[NSCalendar currentCalendar] dateByAddingComponents:components toDate:currentDate options:0];
[components release];
I'm trying to get one month from the current date.
Below is what I have and it is returning: 4027-09-24 16:59:00 +0000. currentDate is right. What's going on?
// Get todays date to set the monthly subscription expiration date
NSDate *currentDate = [NSDate date];
NSLog(#"Current Date = %#", currentDate);
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMonthCalendarUnit | NSDayCalendarUnit | NSYearCalendarUnit fromDate:currentDate];
dateComponents.month = dateComponents.month + 1;
NSDate *currentDatePlus1Month = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:currentDate options:0];
NSLog(#"Date = %#", currentDatePlus1Month);
Try this instead:
// Get todays date to set the monthly subscription expiration date
NSDate *currentDate = [NSDate date];
NSLog(#"Current Date = %#", currentDate);
NSDateComponents *dateComponents = [NSDateComponents new];
dateComponents.month = 1;
NSDate *currentDatePlus1Month = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:currentDate options:0];
NSLog(#"Date = %#", currentDatePlus1Month);
NSDate *currentDate = [NSDate date];
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:currentDate];
// Get necessary date components
[components month]; //gives you month
[components day]; //gives you day
[components year]; //gives you year
How to get the first day of a week for a date
this seems more easy at it is, since :
when the week starts with sunday, i need to get back the sunday date
if it starts on monday, i need to get the monday date
the input date is any date in week with time... i tried several approaches, but the edge case make it difficould
i made a function, which however doesn't work in 100% (not sure about the [components setDay: -weekday + 2];)
- (NSDate *)firstDateOfWeek {
NSCalendar * calendar = [NSCalendar currentCalendar];
NSDateComponents *weekdayComponents = [calendar components:(NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:self];
// because sunday is 0, we need it to be 6
NSInteger weekday = (([weekdayComponents weekday] + 6) % 7);
NSDateComponents *components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:self];
[components setDay: -weekday + 2];
return [calendar dateFromComponents:components];
}
It is easier to use the rangeOfUnit calendar method, which handles "start of the week" correctly according to the current locale:
NSDate *date = your date;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *startOfWeek;
[calendar rangeOfUnit:NSWeekOfYearCalendarUnit
startDate:&startOfWeek
interval:NULL
forDate:date];
Using NSDateComponents, it would work as follows (assuming that a week has 7 days):
NSDate *date = your date;
NSDateComponents *comp = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSWeekdayCalendarUnit
fromDate:date];
NSDate *startOfDay = [calendar dateFromComponents:comp];
NSInteger diff = (NSInteger)[calendar firstWeekday] - (NSInteger)[comp weekday];
if (diff > 0)
diff -= 7;
NSDateComponents *subtract = [[NSDateComponents alloc] init];
[subtract setDay:diff];
NSDate *startOfWeek = [calendar dateByAddingComponents:subtract toDate:startOfDay options:0];