Create NSDate at specific time x days from now - iphone

I'm trying to learn Objective-C/iPhone SDK and right now I'm doing a kind of to-do app playing with local notifications.
I have a "timeOfDay" ivar stored as an NSDate from a DatePicker and a "numberOfDays" ivar stored as an NSNumber.
When I press a specific button, I would like to schedule a local notification x numberOfDays from the time the button is pressed but at the specific timeOfDay.
I seems easy to add an NSTimeInterval to the current date which would give me the a way to schedule the notification numberOfDays from current time but adding the timeOfDay feature makes it more complex.
What would be the correct way of achieving this?
Thanks

Use NSDateComponents to add time intervals to an existing date while respecting all the quirks of the user's current calendar.
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
// Get the year, month and day of the current date
NSDateComponents *dateComponents = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit| NSDayCalendarUnit) fromDate:[NSDate date]];
// Extract the hour, minute and second components from self.timeOfDay
NSDateComponents *timeComponents = [calendar components:(NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:self.timeOfDay];
// Apply the time components to the components of the current day
dateComponents.hour = timeComponents.hour;
dateComponents.minute = timeComponents.minute;
dateComponents.second = timeComponents.second;
// Create a new date with both components merged
NSDate *currentDateWithTimeOfDay = [calendar dateFromComponents:dateComponents];
// Create new components to add to the merged date
NSDateComponents *futureComponents = [[NSDateComponents alloc] init];
futureComponents.day = [self.numberOfDays integerValue];
NSDate *newDate = [calendar dateByAddingComponents:futureComponents toDate:currentDateWithTimeOfDay options:0];

There is a pretty simple method to do this that won't involve as many lines of code.
int numDays = 5;
myDate = [myDate dateByAddingTimeInterval:60*60*24*numDays];

+ (id)dateWithTimeInterval:(NSTimeInterval)seconds sinceDate:(NSDate *)date
That should give you what you're looking for.

Related

How to store and compare time data objects

This should be really simple!
I have a shop, it opens at 8:30 and closes at 17:00. I want my app to say the shops current open or currently closed.
Whats the best way to store my open_time and close_time? Store them as seconds since the start of the day, i.e. 30600 and 63000?
This make sense, but how do I get the current time right now, in seconds since the begining of today, so I can check if current_time is between open_time and close_time, i.e. open!!
Thanks in advance!
This problem isn't quite as trivial as you may think. You have to work with dates very carefully. The best solution is to store all of your open and close times as dates. Here is some code for creating your open/close times and comparing them:
NSDate * now = [NSDate date];
NSCalendar * calendar = [NSCalendar currentCalendar];
NSDateComponents * comps = [calendar components:~(NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:now];
[comps setHour:8];
[comps setMinute:30];
NSDate * open = [calendar dateFromComponents:comps];
[comps setHour:17];
[comps setMinute:0];
NSDate * close = [calendar dateFromComponents:comps];
if ([now compare:open] == NSOrderedDescending && [now compare:close] == NSOrderedAscending) {
// The date is within the shop's hours.
}
else {
// The date is not within the shop's hours.
}
Here's what I did:
Grab the current date.
Get the components of the date, except hours, minutes, and seconds.
Set the hour and minutes.
Create an open time.
Repeat steps 3-4 for close time.
Compare open and close times to now.
If you ever need to do any modification of dates, you should always use NSCalendar and NSDateComponents. Check out this answer for why it's so important.
I think a clearer solution would be to use NSDate objects with only hour/minute components present.
Basically, somewhere in your app you need to store the shop's open/close times as such:
NSCalendar *calendar = [[NSCalendar alloc]
initWithCalendarIdentifier: NSGregorianCalendar];
NSDateComponents *openTime = [[NSDateComponents alloc] init];
[openTime setHour: 12];
[openTime setMinute: 30];
NSDate *openDate = [calendar dateFromComponents: openTime];
[calendar release];
And if you need to see whether the current time is between two such NSDate objects you could have a method like this:
- (BOOL)currentTimeIsInBetween: (NSDate *)date1 andDate: (NSDate *)date2 {
NSCalendar *calendar = [[NSCalendar alloc]
initWithCalendarIdentifier: NSGregorianCalendar];
NSDateComponents *currentComponents = [calendar components:
(NSMinuteCalendarUnit | NSHourCalendarUnit)
fromDate: [NSDate date]];
NSDate *currentAdjusted = [calendar dateFromComponents: currentComponents];
[calendar release];
if ([currentAdjusted compare: date1] == NSOrderedAscending)
return NO;
if ([currentAdjusted compare: date2] == NSOrderedDescending)
return NO;
return YES;
}
EDIT: Seems like user rbrown was a bit faster than me, we are suggesting the same approach.
You can do something like this.
NSDate *today = // code for getting today date at 0 oclock
NSDate *now = [NSDate date];
double second = [now timeIntervalSinceDate:today];
Now you got time in second since the start of the day for compare.

How can I create a date with no hours in the current time zone?

This question follows on from a previous question...
How do I create the current date (or any date) as an NSDate without hours, minutes and seconds?
I would use this code as follows...
NSDate *todaysDate = [General makeAbsoluteNSDate:[NSDate date]];
My problem is that I have users in different countries and UTC isn't their timezone and the date produced by this function at certain times of the day won't be correct.
How do I get the current time zone to correct my function ?
Or should I be using a different approach ?
Heres the function I've been using...
+ (NSDate *)makeAbsoluteNSDate:(NSDate*)datSource {
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:
NSGregorianCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"UTC"]];
NSDateComponents *dateComponents = [calendar components:NSYearCalendarUnit |
NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:datSource];
[dateComponents setHour:0];
[dateComponents setMinute:0];
[dateComponents setSecond:0];
NSDate *midnightUTC = [calendar dateFromComponents:dateComponents];
[calendar release];
return midnightUTC;
}
You get the timezone object from this call:
[NSTimeZone localTimeZone]
And you can use the secondsFromGMT method to figure out the difference and create a date with the timezone.
You can even build a Category for NSDate that includes a method to transform a date into the current timezone date, which would be even simpler.

How to get do calculations including date from datePicker in Xcode/

I need to build a mortgage calculator for iPhone as a task and I need to be able to read startdate from DatePicker in MainView, then an enddate for another DatePicker in FlipView and calculate the difference in the number of months between both dates. As I am new to Apple programming I do not know how to do it. Help, please :)
From your edit, it seems that the more specific problem you have is reading the date from a UIDatePicker
From the docs, the method you need to call is date
NSDate *dateFromPicker = [myDatePickerObject date];
you could use - (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate .
The result will be NSTimeInterval which will be a double that is equivalent to the amount of seconds. Take that amount and divide by the appropriate number (seconds? 60. hours? 360. etc…)
The code would resemble:
[[datePicker1 date] timeIntervalSinceDate:[datePicker2 date]];
Good luck!
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *differenceComponents = [calendar components:NSMonthCalendarUnit | NSDayCalendarUnit fromDate:startDate toDate:endDate options:0];
int monthDifference = differenceComponents.month;

Time picker problem with OS4?

I have an app which I am updating to OS4. In this I use a time picker. From this I want to get an hour and minute as an integar. This is the code I used previously for this...
NSDate *selected = [timePicker date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit| NSMinuteCalendarUnit |NSSecondCalendarUnit;
NSDateComponents *compsDur = [gregorian components:unitFlags fromDate:selected];
int hDur = [compsDur hour];
int mDur = [compsDur minute];
int sDur = [compsDur second];
[gregorian release];
Now all was working fine here. My problem is that when I update to OS4 if I change my phones time settings say from the UK to the US I get a random value not what the user has entered.
To give you a specific example, on UK time I set the time for 1 minute, I get a return value for mDur as 1. If I then change my phone to New York time I get 19 hours and 6 minutes? What's going on?
I think this might be related to an undocumented change to the UIDatePicker in iOS4 where it defaults to (what I think is) GMT as the time zone.
You can set the time zone of the UIDatePicker to the system time zone so the user gets the expected experience.
yourDatePicker.timeZone = [NSTimeZone systemTimeZone];

Difference between 2 NSDates, excluding Weekends?

For those familiar with Excel, I'm trying to use a similiar NETWORKDAYS function within Cocoa.
Can anyone help with the type of info I'll need to construct an NSDate catagory that can give me only the working days betweek two dates?
many thanks
Nik
I know that I'll give is not optimized, but it's just to give you a way to explore.
You can use the NSCalendar and the NSDateComponents like that:
// Date of today
NSDate *today = [NSDate date];
// init the gregorian calendar
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
// Retrieve the NSDateComponents for the current date
NSDateComponents *weekdayComponents = [gregorian components:(NSDayCalendarUnit | NSWeekdayCalendarUnit) fromDate:today];
// Number of the day in the week (e.g 2 = Monday)
NSInteger weekday = [weekdayComponents weekday];
(see Calendars, Date Components, and Calendar Units)
From there you start from your first date and you iterate this for each day until your end date and using the weekday you can determine if the day is during a weekend or not. (I repeated that's not optimized but it's just a track)