UIDatePicker: help to convert pseudo code into objc code - ios

I am trying to implement some pseudo code I have for the date picker. However I am unsure of how to add a minute value to adjust an NSDate object.
Here is the pseudo code:
//minTime is an NSDate object
minTime = currentTime + 30mins - (currentTime % 15)
(currentTime % 15) means that the user can only select in 15mins intervals, and must be 15mins from the current 15min interval. For example, if its 10:50, the user should only be able to select 11:15 from the UIDatePicker. If is 10:20, the user should only be able to select 10:45.
I know how to get the currentTime using [NSDate date] but I do not know how to add mins to it and adjust it.

It is not considered good practice to work with time intervals when working with dates and times. The best solution is to use NSDateComponents to add time periods.
NSDateComponents* dc = [NSDateComponents new];
dc.minutes = 15;
NSDate* newDate = [[NSCalendar currentCalendar] dateByAddingComponents:dc toDate:oldDate options:0];

You can add some minutes to a NSDate using :
NSDate *nowDate = [NSDate date];
NSDate *nowDateAnd2moreMinutes = [nowDate dateByAddingTimeInterval:2*60]; //This add 2 minutes (2 * 60sec)
More information in apple documentation.
Edit I wrote a little function that add minutes :
+(NSDate) addMinutes:(int) minutes toDate:(NSDate) date{
return [date dateByAddingTimeInterval:minutes*60];
}
Bonus : Function that add minutes and seconds to a date
+(NSDate) addMinutes:(int) minutes andSeconds:(int) sec toDate:(NSDate) date{
return [date dateByAddingTimeInterval:(minutes*60)+sec];
}

Related

Adding 30 seconds to NSDate [duplicate]

This question already has answers here:
How to add a time interval to an NSDate?
(5 answers)
Closed 7 years ago.
How can I convert an NSDate to seconds? I need it in seconds so that I can added 30 secs to the date and then convert back to NSDate to schedule a local notification. Any better ways of doing that are welcome too.
You can use dateByAddingTimeInterval and pass in the value as 30. This will return you an NSDate which will be 30 secs ahead.
NSDate *newDate = [previousDate dateByAddingTimeInterval:30];
Date and Time Programming Guide states that NSDateComponents should be used to perform date calculations.
Quote from the same document:
You should use the provided methods for dealing with calendrical calculations because they take into account corner cases like daylight savings time starting or ending and leap years.
So to add 30 seconds to a date, you should do something like this:
NSDate * date = [NSDate date];
NSCalendar * currentCalendar = [NSCalendar currentCalendar];
NSDateComponents * dateComponents = [NSDateComponents new];
[dateComponents setSecond:30];
NSDate * newDate = [currentCalendar dateByAddingComponents:dateComponents toDate:date options:0];
NSLog(#"%#", newDate);

Store time zone independent time-only in NSDate object

I am creating an app which includes a timetable feature, allowing the user to specify periods in a particular day (e.g. Period 1 goes from 9:00 to 10:00; Period 2 goes from 10:00 to 11:00 and so on). As the app is backed by Core Data it seems sensible to store the periods as Core Data managed objects with two NSDate attributes: startTime and endTime.
Assuming that the periods cannot span multiple days, the date in the NSDate objects is irrelevant - I am only interested in the time. While one approach is to simply use NSDateComponents to extract the time (and ignore the date) if I am doing a comparison of NSDate objects, or sorting based upon those objects, then if the dates are different that will affect the comparison or sort. I was thinking that one way around this problem is to manually the startTime and endTime attributes to have the same (arbitrarily) chosen date. Is this the best way around the issue?
Additionally, the times (i.e. NSDate objects) need to be time zone independent. If the user travels from say Australia to the USA then I don't want all the times to now show they have a class in the middle of the night! Compensating for time zone changes is not relevant in this app, so I would like the times to stay static regardless of time zone. I would appreciate advice on this aspect too.
Thanks in advance for any assistance!
If you don't need the "day date" I would recommend to not use NSDate at all, otherwise you will run into various issues. As said in the comments NSDate is not timezone aware, this means you will do a lot of unnecessary conversions to make sure that your app works in all timezones.
I would as well use the approach to save seconds since midnight, or have two fields for hours and minutes since midnight. That basically is local time, always.
To get this information from a UIDatePicker you have to convert the NSDate into NSDateComponents
- (IBAction)datePickerChanged:(UIDatePicker *)sender {
NSDate *date = sender.date;
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
calendar.timeZone = sender.timeZone;
NSDateComponents *components = [calendar components:NSHourCalendarUnit|NSMinuteCalendarUnit fromDate:date];
NSInteger hours = components.hour;
NSInteger minutes = components.minute;
NSLog(#"%02ld:%02ld", (long)hours, (long)minutes);
NSInteger secondsSinceMidnight = hours * (60*60) + minutes * 60;
// save to core data
}
When you want to show your time in the datePicker you have to go the opposite way, you have to create a NSDate (that, for timezone reasons happens to be today) from the saved components. e.g.:
// get from core data
NSInteger secondsSinceMidnight = 8 * (60*60) + 30 * 60;
NSInteger minutes = (secondsSinceMidnight / 60) % 60;
NSInteger hours = (secondsSinceMidnight / 3600);
NSLog(#"%02ld:%02ld", (long)hours, (long)minutes);
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
calendar.timeZone = datePicker.timeZone;
// use today as day, to avoid timezone issues
NSDateComponents *components = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:[NSDate date]];
components.hour = hours;
components.minute = minutes;
datePicker.date = [calendar dateFromComponents:components];

Timezone Calculation Issues

I am making a countdown timer and I want it to globally countdown to Christmas. Therefore I have my timestamp value of 1387929600 which is dec 25 00:00:00. I am adjusting that value according to the different time zones and I am doing it like this:
NSDate *firstDate = [NSDate dateWithTimeIntervalSince1970:1387954801];
NSTimeZone *tz = [NSTimeZone localTimeZone];
int tzInt = [tz secondsFromGMTForDate:firstDate];
int timeDifference = tzInt+1387954801;
xmasDate = [NSDate dateWithTimeIntervalSince1970:timeDifference];
I take the firstDate and do secondsFromGMTForDate and then add it to the original timestamp number to get the xmasDate adjusted for time zones.
This general approach seems to work however the secondsFromGMTForDate is not calculating correctly.
For example when I set my phone to the current time zone it still wants to subtract "-25200" from the timestamp time when it should be zero since its the current time zone.
Am I correct in saying that? I might be missing something in the calculation and maybe I have to add to the timestamp number but I'm not sure.
Any help would be greatly appreciated.
By adding tzInt to a timestamp in GMT, you're doubling the effect of time zone difference instead of cancelling it.
For example, if your timezone is 25200 seconds behind GMT (tzInt=-25200), you need to add 25200 to 1387929600, as Christmas will come later in your time zone.
So the correct calculation of timeDifference is the following:
int timeDifference = 1387954801 - tzInt;
Otherwise the code looks correct, but I'd use the following code instead, which, I think, is easier to understand:
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay:25];
[components setMonth:12];
[components setYear:2013];
NSDate *xmasDate = [[NSCalendar currentCalendar] dateFromComponents:components];
NSTimeInterval secondsLeft = [xmasDate timeIntervalSinceNow];

Calculate time difference between two NSDates with different locales

I have a current NSString in the format of 2010-04-23 00:00:00 and then I'm trying to get the number of days passed from the current day. However, I'm not sure how to handle when the user changes their locale to Thailand for example.
Here is some of the code.
NSString *start = #"2010-04-23 00:00:00";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSDate *date = [formatter dateFromString:start];
//Region Format Thailand
NSDate *today = [[NSDate alloc] init];
NSTimeInterval difference = [today timeIntervalSinceDate:start];
int numberOfDays = difference / 86400;
What would be the correct way to handle this situation so the number of days difference is accurate?
Dates are complicated.
If you want a difference in days, hours, minutes, seconds, that's easy: Convert everything to NSDate, calculate the difference in seconds, convert to days, hours, minutes, seconds.
Anything else, you need to first define what results you actually want. Today at 1am and 11pm is the same day, but today 11pm and tomorrow 1am are different days - even though in the first case the difference is 22 hours, in the second case just two hours. So you have to define what you want. You have to define for which case you want a result of "0 days" and for which case you want a result of "1 days".
And if you change time zones, some dates will move to a different day, some won't.
It's up to you to decide what result you want. In any case, I'd convert all dates to the relevant time zone, extract the day, and calculate days differences from that.
You need to convert the date into epoch time.
- (NSTimeInterval)timeIntervalSince1970
After you do that you can use the below code, to find the time difference in seconds and compare them.
NSDate* date1 = [NSDate date];
NSDate* date2 = [NSDate date];
NSTimeInterval secs = [date1 timeIntervalSinceDate:date2];
if (secs < 0)
{
NSLog("less");
}
else if (secs > 0)
{
NSLog("greater");
}
else
{
NSLog(#"same");
return NSOrderedSame;
}

iOS: Formula for alert notifications

I'm trying to write an application that will send the user an alert in the Notification Center 60 hours before the date arrives. Here is the code:
localNotif.fireDate = [eventDate dateByAddingTimeInterval:-60*60*60];
I was wondering if the -60*60*60 formula will work to alert them 60 hours prior to the date? I'm not sure at all how the formula works, I would like to set it up to alert 10 minutes before the date for testing purposes, then change it back to 60 hours once I confirm that everything is correct. Does any one know the formula to use for both of these?
Any help is much appreciated, thank you!
A crude but easy-to-code way is to add/subtract seconds from an NSDate directly:
NSDate *hourLaterDate = [date dateByAddingTimeInterval: 60*60];
NSDate *hourEarlierDate = [date dateByAddingTimeInterval: -60*60];
You can see how it works by logging the dates:
NSDate *now = [NSDate date];
NSDate *hourLaterDate = [now dateByAddingTimeInterval: 60*60];
NSLog(#"%# => %#", now, hourLaterDate);
In this approach a date is interpreted as a number of seconds since the reference date. So, internally it's just a big number of type double.
A tedious-to-code but pedantically correct way to do these calculations is by interpreting dates as dates expressed in a calendar system. The same thing achieved as calendrical calculations:
NSDateComponents *hour = [[NSDateComponents alloc] init];
[hour setHour: 1];
NSCalendar *calendar= [[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar];
NSDate *hourLaterDate = [calendar dateByAddingComponents: hour
toDate: date
options: 0];
[hour release];
[calendar release];
These calculations take into account time zones, daylight saving time, leap years, etc. They can also be more expressive in terms of what you're calculating.
Before using any of these approaches you have to decide what exactly you need: a timestamp or a full-blown calendar date.

Resources