xcode NSCalendarUnit shows 3 month ahead - xcode

I am trying to calculate number of days in current month
today = [NSDate date];
NSLog(#"%#", today);
//calculate how much days in current month
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSRange days = [cal rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:today];
NSUInteger numberOfDaysInMonth = days.length;
NSLog(#"%d Days in month:%i", numberOfDaysInMonth, NSMonthCalendarUnit);
// end calculating
In log it shows August month instead of May
Why it happens? What I missed?
Thanks
2013-05-07 21:39:01.344 NsTimer[89023:c07] 2013-05-07 18:39:01 +0000
2013-05-07 21:39:01.345 NsTimer[89023:c07] 31 Days in month:8
ANSWER:
Thanks #artur
This is a right code
today = [NSDate date];
NSLog(#"%#", today);
//calculate how much days in current month
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
int units = NSMonthCalendarUnit;
NSDateComponents *comps = [cal components:units fromDate:today];
NSRange days = [cal rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:today];
NSUInteger numberOfDaysInMonth = days.length;
NSLog(#"%d Days in month:%i", numberOfDaysInMonth, comps.month);
// end calculating
Log now shows:
2013-05-07 22:25:04.855 NsTimer[89623:c07] 2013-05-07 19:25:04 +0000
2013-05-07 22:25:04.856 NsTimer[89623:c07] 31 Days in month:5

You log NSMonthCalendarUnit as integer (%i). It is just enum flag value, accidentally 8. To show month number, you should extract it with [[calendar components:NSMonthCalendarUnit fromDate:today] month].

Related

Get first day in a month from NSCalendar

I have this subset of a method that needs to get day one of the current month.
NSDate *today = [NSDate date]; // returns correctly 28 february 2013
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
components.day = 1;
NSDate *dayOneInCurrentMonth = [gregorian dateByAddingComponents:components toDate:today options:0];
dayOneInCurrentMonth then prints out 2013-03-01 09:53:49 +0000, the first day of the next month.
How do I get day one of the current month?
Your logic is wrong: Instead of setting the date's day to 1, you're adding a day to the current date.
Try something like that:
NSDate *today = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorian components:(NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit) fromDate:today];
components.day = 1;
NSDate *dayOneInCurrentMonth = [gregorian dateFromComponents:components];
You want [NSCalender dateFromComponents:] instead:
NSDate *dayOneInCurrentMonth = [gregorian dateFromComponents:components];
Easy way of getting to the 1st from a given date:
NSDate *first = [gregorian dateBySettingUnit:NSCalendarUnitDay value:1 ofDate:date options:0];
Easy Way to get first and last date of previous month is :
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *comp = [gregorian components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay ) fromDate:[NSDate date]];
//TO GET PREVIOUS MONTH LAST DAY
[comp setMonth:[comp month]];
[comp setDay:1];
NSDate *tDateMonth = [gregorian dateFromComponents:comp];
NSLog(#"LAST DAY OF PREVIOUS MONTH ; %#", tDateMonth);
//TO GET PREVIOUS MONTH FIRST DAY
[comp setMonth:[comp month]-1];
[comp setDay:3];
NSDate *td = [gregorian dateFromComponents:comp];
NSLog(#"FIRST DAY OF PREVIOUS MONTH ; %#", td);
Hope this helps
By creating new variable is expensive on memory usage, it's better using date formatter to get the first day of the current month
today = [NSDate date];
firstDayDateFormatter = [[NSDateFormatter alloc] init];
[firstDayDateFormatter setDateFormat:#"01-MM-yyyy"];
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
[dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:#"en_US"]];
firstDayOfTheMonth = [mdfDateFormat dateFromString:[firstDayDateFormatter stringFromDate:today]];
NSDate *startDate = nil;
[[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitMonth startDate:&startDate interval:NULL forDate:date];
return startDate;

How can I get an NSDate for the first day of the next week of the month

Given an arbitrary date, I need to find the date of the first day of the next week of the month. Note that it is not as simple as adding 7 days to the current date because the last week of the month may be less than 7 days. Here is the code I'm using now:
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* components = [calendar components:NSWeekOfMonthCalendarUnit|NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSDayCalendarUnit fromDate:currentDate];
NSLog(#"week of month: %ld", [components weekOfMonth]);
[components setWeekOfMonth:[components weekOfMonth] + 1];
NSLog(#"new week of month: %ld", [components weekOfMonth]); //week of month is now 2
[components setWeekday:1];
NSDate *nextWeek = [calendar dateFromComponents:components];
As an example, currentDate is set to 2012-10-01. In this example nextWeek is always 2012-10-01. It appears that sending setWeekOfMonth: does not increment the other date components in the NSDateComponents object. Do I have the wrong date components configured, or is setWeekOfMonth: not supposed to work like that?
So.... Let's start with an NSDate and an NSCalendar:
NSDate *date = ...;
NSCalendar *cal = [NSCalendar currentCalendar];
Figure out what day of the week that date is:
NSInteger weekdayOfDate = [cal ordinalityOfUnit:NSWeekdayCalendarUnit inUnit:NSWeekCalendarUnit forDate:date];
NSInteger numberOfDaysToStartOfCurrentWeek = weekdayOfDate - 1;
Let's move that date into the next week:
NSDateComponents *oneWeek = [[NSDateComponents alloc] init];
[oneWeek setWeek:1]; // add one week
[oneWeek setDay:-numberOfDaysToStartOfCurrentWeek]; // ... and subtract a couple of days to get the first day of the week
NSDate *startOfNextWeek = [cal dateByAddingComponents:oneWeek toDate:date options:0];
At this point, you have a date that points to the first day of the next week. Now we should verify that it's still in the same month:
NSDateComponents *monthOfNextWeek = [cal components:NSMonthCalendarUnit fromDate:startOfNextWeek];
NSDateComponents *monthOfThisWeek = [cal components:NSMonthCalendarUnit fromDate:date];
if ([monthOfNextWeek month] != [monthOfThisWeek month]) {
// the first day of the next week is not in the same month as the start date
}
When I run this, I get that the start of next week is 30 Dec 2012 (a Sunday, because my calendar's weeks start on Sunday).
If, however, I want the first day of the week to start on Monday, I can preface this code with:
[cal setFirstWeekday:2]; // the first day of the week is the second day (ie, Monday, because Sunday = 1)
If I do this, then the startOfNextWeek results in 31 Dec 2012.
Will this be a valid answer :
NSDateFormatter *dateFormatter=[NSDateFormatter new];
[dateFormatter setLocale:[[NSLocale alloc]initWithLocaleIdentifier:#"en_US_POSIX"]];
[dateFormatter setDateFormat:#"EEE"];
NSDate *date=[NSDate date];
NSString *dateString=[dateFormatter stringFromDate:date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar];
NSDateComponents *components = [NSDateComponents new];
[calendar setFirstWeekday:1];//1 for Mon
NSDate *newDate=date;
while (![dateString isEqualToString:#"Mon"]) {
components.day = 1;
newDate = [calendar dateByAddingComponents:components toDate:newDate options:0];
dateString=[dateFormatter stringFromDate:newDate];
}
NSLog(#"Upcoming week Date=%#",newDate);

NSDate hours are not correct after constructing date from components

I'm trying to construct a date from two different dates. When I break down both dates into their respective components and re-assemble them into the new date.. everything seems to be correct except the hours. Im sure its something simple that has to do with the timezone or the NSGregorianCalendar, but I am new to iOS, and programming NSCalendar. Im hoping someone will catch the simple mistake Im making.
//grab today's date so we can brek it down into components
NSDate *todayDate = [NSDate date];
NSLog(#"Todays Date: %#", todayDate);
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
//break down the stored date into components
NSDateComponents *theTime = [gregorian components:(NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:storedIncorrectDate];
NSLog(#"Incorrect Calendar Components %#", theTime);
NSDateComponents *todayCalendarComponents = [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:todayDate];
NSInteger currentYear = [todayCalendarComponents year];
NSLog(#"The Year: %i", currentYear);
NSInteger currentMonth = [todayCalendarComponents month];
NSLog(#"The Month: %i", currentMonth);
NSInteger currentDay = [todayCalendarComponents day];
NSLog(#"The Day: %i", currentDay);
NSLog(#"Today's Calendar Components %#", todayCalendarComponents);
NSInteger theHours = [theTime hour];
NSLog(#"Hours: %i", theHours);
NSInteger theMinutes = [theTime minute];
NSLog(#"Minutes: %i", theMinutes);
NSInteger theSeconds = [theTime second];
NSLog(#"Seconds: %i", theSeconds);
//build my new date and store it before we play the affirmation.
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setHour:theHours];
[components setMinute:theMinutes];
[components setSecond:theSeconds];
[components setYear:currentYear];
[components setMonth:currentMonth];
[components setDay:currentDay];
[components setTimeZone:[NSTimeZone localTimeZone]];
NSLog(#"The Components: %#", components);
NSCalendar *updatedCal = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *revisedCorrectedDate = [updatedCal dateFromComponents:components];
NSLog(#"The Hours: %i", theHours);
NSLog(#"The New and Corrected Date: %#", revisedCorrectedDate);
The result of the log printing the revisedCorrectedDate shows everything correct that I set except the hours. This has to be a simple fix.. I just don't see it. Thank you in advance!
Are you sure it's incorrect? When I run this code, I get:
2012-06-03 18:13:36.130 Untitled[39805:707] The New and Corrected
Date: 2012-06-04 01:13:36 +0000
It's currently 6/3/12 18:13:36 here, and the date displayed is 6/4/12 01:13:36, which is the correct time, in UTC (notice the +0000 at the end).

Stripping the time out of an NSDate

I have seen many version of the following code to remove the time element from an NSDate.
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
unsigned int intFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *components = [cal components:intFlags fromDate:now];
NSDate *today = [cal dateFromComponents:components];
Trouble is it does not work as expected. I am currently in British summertime (BST). If I run this code now, now=#"2012-07-07 19:24:06 +0000"
today=#"2012-07-06 23:00:00 +0000"
What I want to see is today=#"2012-07-07 00:00:00 +0000"
I can only guess that it has something to do with daylight saving. Any ideas?
You are getting midnight BST (which is GMT+1 hour), which is the same as 23:00 GMT (+0000).
[NSDate date] will return a date in the current timezone, so your date is in BST. Have you also tried setting the timezone to GMT:
[components setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
There is no such thing as a date without a time, because there never was a point in time that did not have a time (according to our current calendaring systems, anyway), and a date is just a point in time. Ergo, a date necessarily must have a time.
What you can do, is format a date such that the time isn't displayed. For that, you use an NSDateFormatter:
NSDate *date = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:date];
NSDate *todayAtMidnight = [calendar dateFromComponents:components];
NSString *formatted = [NSDateFormatter localizedStringFromDate:todayAtMidnight dateStyle: NSDateFormatterMediumStyle];
// "formatted" is now something like "Jul 8, 2012".
// It varies according to your locale and user settings.
Technically the first bit (of setting the time portion to midnight) isn't necessary if you're just formatting a date without the time, but you can leave it in if it makes you feel like you're actually "removing the time". :)
Add a
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
to avoid the use of the default values. Documentation doesn't even say what these values are, so they might not be "0".

How to create a specific date in the distant past, the BC era

I’m trying to create a date in the BC era, but failing pretty hard. The following returns ‘4713’ as the year, instead of ‘-4712’:
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [NSDateComponents new];
[components setYear: -4712];
NSDate *date = [calendar dateFromComponents:components];
NSLog(#"%d", [[calendar components:NSYearCalendarUnit fromDate: date] year]);
Any idea what I’m doing wrong?
UPDATE: Working code
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [NSDateComponents new];
[components setYear: -4712];
NSDate *date = [calendar dateFromComponents:components];
NSDateComponents *newComponents = [calendar components:NSEraCalendarUnit|NSYearCalendarUnit fromDate:date];
NSLog(#"Era: %d, year %d", [newComponents era], [newComponents year]);
This prints 0 for the era, just as Ben explained.
Your code is actually working fine. Since there’s no year zero, -4712 is the year 4713 BC. If you check the era component you’ll see that it’s zero, which in the Gregorian calendar indicates BC. Flip that negative sign and you’ll see 4712 AD (era 1).

Resources