Is there a better way to find midnight tomorrow? - cocoa

Is there a better way to do this?
-(NSDate *)getMidnightTommorow {
NSCalendarDate *now = [NSCalendarDate date];
NSCalendarDate *tomorrow = [now dateByAddingYears:0 months:0 days:1 hours:0 minutes:0 seconds:0];
return [NSCalendarDate dateWithYear:[tomorrow yearOfCommonEra]
month:[tomorrow monthOfYear]
day:[tomorrow dayOfMonth]
hour:0
minute:0
second:0
timeZone:[tomorrow timeZone]];
}
Note that I always want the next midnight, even if it happens to be midnight when I make that call, however if it happens to be 23:59:59, I of course want the midnight that is coming in one second.
The natural language functions seem flaky, and I'm not sure what Cocoa would do if I pass 32 in the "day" field. (If that'd work I could drop the [now dateByAddingYears:...] call)

From the documentation:
Use of NSCalendarDate strongly
discouraged. It is not deprecated yet,
however it may be in the next major OS
release after Mac OS X v10.5. For
calendrical calculations, you should
use suitable combinations of
NSCalendar, NSDate, and
NSDateComponents, as described in
Calendars in Dates and Times
Programming Topics for Cocoa.
Following that advice:
NSDate *today = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
components.day = 1;
NSDate *tomorrow = [gregorian dateByAddingComponents:components toDate:today options:0];
[components release];
NSUInteger unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;
components = [gregorian components:unitFlags fromDate:tomorrow];
components.hour = 0;
components.minute = 0;
NSDate *tomorrowMidnight = [gregorian dateFromComponents:components];
[gregorian release];
[components release];
(I'm not sure offhand if this is the most efficient implementation, but it should serve as a pointer in the right direction.)
Note: In theory you can reduce the amount of code here by allowing a date components object with values greater than the range of normal values for the component (e.g. simply adding 1 to the day component, which might result in its having a value of 32). However, although dateFromComponents: may tolerate out-of-bounds values, it's not guaranteed to. You're strongly encouraged not to rely on it.

Nope - it'll be the same way you use to find midnight today.

NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDate *tomorrow = [NSDate dateWithTimeIntervalSinceNow:(24 * 60 * 60)];
NSDateComponents *components = [gregorian components:(NSYearCalendarUnit |
NSMonthCalendarUnit |
NSDayCalendarUnit)
fromDate:tomorrow];
NSDate *midnight = [gregorian dateFromComponents:components];

[NSDate dateWithNaturalLanguageString:#"midnight tomorrow"];

Convert your current date and time to a Unix date (seconds since 1970) or DOS style (since 1980), then add 24 hours and convert it back. Then reset the hours, minutes and seconds to zero to get to midnight.

You could try this way:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:1];
NSDate *tomorrow = [calendar dateByAddingComponents:comps toDate:[NSDate date] options:0]; //it gives us tomorrow with current time
NSDate *midnight = [calendar startOfDayForDate:tomorrow]; //here we get next midnight
It is also easy to retrieve the seconds interval if needed to set up an NSTimer:
double intervalToMidnight = midnight.timeIntervalSinceNow;

Related

How to calculate and display 4 other days from the day i add in date picker and set local notification to it?

In my App, When i select a day in the datepicker it should automatically calculate and display 4 other days and also it should notify on the corresponding days. For Eg. if i enter 19-08-2014, it should calculate and display the 3rd day, the 7th day, the 14th day and the 21st day from 19-08-2014(the day i entered in datepicker).
How would i achieve this. Any help would be greatly appreciated.
I have added my current code for your reference. This doesnt serve my purpose.
Kindly Help.
(IBAction)save:(UIButton *)sender {
NSDate *pickerDate = [self.picker date];
UILocalNotification *localNotif = [[UILocalNotification alloc]init];
//localNotif.alertBody = _enterText.text;
localNotif.alertBody = #"Please Take Your Rabipur Dosage";
localNotif.fireDate = pickerDate;
localNotif.timeZone = [NSTimeZone defaultTimeZone];
localNotif.soundName = (UILocalNotificationDefaultSoundName);
localNotif.applicationIconBadgeNumber = 1;
//localNotif.repeatInterval = NSDayCalendarUnit;
[[UIApplication sharedApplication]scheduleLocalNotification:localNotif];
[self dismissViewControllerAnimated:YES completion:nil];
}
Create an NSDateComponents object with the date difference you want to add, and add it to pickerDate via NSCalendar -dateByAddingComponents:toDate:options. Then create your notification based on the resulting date.
In this case, something like this:
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setDay:3];
NSDate *reminderDate = [gregorian dateByAddingComponents:offsetComponents toDate:pickerDate options:0];
Repeat for 7th, 14th, and 21st day.

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;

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".

Set the time of the DatePicker

How do I set the time of the DatePicker at 00:00:00 of the current date?
- (void) awakeFromNib
{
[datePicker setDateValue:[NSDate date]];
NSDate *now = [NSDate date];
int daysToAdd = 364;
NSDate *newDate1 = [now dateByAddingTimeInterval:60*60*24*daysToAdd];
[datePicker1 setDateValue:newDate1];
}
cringe
It looks like you have two different datePickers? datePicker and datePicker1? What's up with that?
Also, this does not do what you're expecting:
NSDate *newDate1 = [now dateByAddingTimeInterval:60*60*24*364];
That is creating a new date that is exactly 31,449,600 seconds in the future. It is not doing anything other than that.
What you want to do is extract all of the date components from the current date and zero them out:
NSDate *now = [NSDate date];
NSDateComponents *nowComponents = [[NSCalendar currentCalendar] components:(NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:now];
// technically these next lines are unnecessary, since we only pulled out the era-year-month-day, but they're included here for understanding/completeness:
[nowComponents setHour:0];
[nowComponents setMinute:0];
[nowComponents setSecond:0];
// now we can turn it back into a date:
NSDate *todayAtMidnight = [[NSCalendar currentCalendar] dateFromComponents:nowComponents];

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