I am making an app to use at school and I want to make a countdown timer to countdown the amount of time between now and the end of school, which for me is 3:00. For example, at 11:15, it will read 3:45.
So far, I have figured out how to make the countdown timer and I have the following code: countdownTimer.text = [Formatter stringFromDate: [NSDate date]];
This code doesn't actually work yet, but I think it will work if I figure out how to subtract the current time from a set time and then use that value where date is, however I am open to other suggestions on how to approach the problem.
You can use NSCalendar method dateBySettingHour:minute:second: to get the NSDate object associated with 3pm today:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
NSDate *schoolOut = [calendar dateBySettingHour:15 minute:0 second:0 ofDate:now options:0];
There are lots of different ways to get the NSDate object associated with 3pm today, but the above is just one example. You could also use components:fromDate of NSCalendar to extract the NSDateComponents of now, then adjust the hour, minute and second and then create a new NSDate object using dateFromComponents (also a NSCalendar method).
Anyway, once you have a NSDate object that represents your target date/time, you can then use NSDateComponentsFormatter to display the time interval between two dates in a nice format.
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute;
formatter.unitsStyle = NSDateComponentsFormatterUnitsStyleFull;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
NSString *string = [formatter stringFromDate:now toDate:schoolOut];
You can adjust the unitsStyle and zeroFormattingBehavior to adjust the format of the string.
Related
How can I save a duration in a plist so that I can load up some sample data in Core Data?
By duration I mean a task has a time duration. Could be 1h12m. Could be 15m.
Using this category
+(NSDate *)dateWithHour:(NSInteger)hour minute:(NSInteger)minute
{
NSDateComponents *components = [[NSDateComponents alloc]init];
components.hour = hour;
components.minute = minute;
NSCalendar *calender = [NSCalendar currentCalendar];
NSDate *date = [calender dateFromComponents:components];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"HH:mm"];
NSLog(#"**Date Utils** %#",[dateFormatter stringFromDate:date]);
return date;
}
I can create a duration of 15minutes
task.duration = [NSDate dateWithHour:0 minute:15];
It outputs to the console as:
0001-01-01 04:29:24 +0000
Which doesn't appear to be 15minutes. It looks like 4h29m24s. If I run the date back through a dateFormatter sure enough it prints out 15m.
How can I input a time duration in the plist as shown below?
What am I missing?
Dates are terribly complicated because of time zones and leap years and leap seconds and so on. They're not suitable for this use case and you will have all kinds of bugs trying to use them.
The correct data type for durations is NSTimeInterval, which is a 64 bit floating point number, in seconds. NSDate uses this data type internally as well.
The easiest way to create a time interval is:
NSDate *aDate = ...
NSDate *anotherDate = ...
NSTimeInterval duration = [aDate timeIntervalSinceDate:anotherDate];
And you'd save it to a plist with NSNumber:
NSNumber *durationNumber = [NSNumber numberWithDouble:duration];
Note that NSTimeInterval is actually a double.
This is probably a simple solution but does anyone know how to delay the NSDate change past midnight? Any insight would be really helpful, thanks!
Edit:
I am currently getting the date this way and displaying a locations data based on that day. But, much like the NSDate is logically supposed to work, it switches to the next day at midnight. I want the date to change at 3am instead of at 12am.
NSDateFormatter *f = [[NSDateFormatter alloc] init];
[f setDateFormat:#"EEEE"];
today = [f stringFromDate:[NSDate date]];
Should I just use the time instead of using NSDate? I am a bit of a noob to iOS so any insight would be helpful. Thanks for your responses already.
I must admit that I do not yet understand why you want to display a "wrong" weekday
name, but the following code should do what you want. This is only one of various ways
to achieve your task.
Convert date to "date components:"
NSCalendar *cal = [NSCalendar currentCalendar];
NSUInteger unitFlags = NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit;
NSDateComponents *comp = [cal components:unitFlags fromDate:[NSDate date]];
Subtract one day if necessary:
if (comp.hour < 3) {
comp.day -= 1;
}
Convert adjusted components back to date:
NSDate *adjustedDate = [cal dateFromComponents:comp];
Your original code, now using the adjusted date:
NSDateFormatter *f = [[NSDateFormatter alloc] init];
[f setDateFormat:#"EEEE"];
NSString *today = [f stringFromDate:adjustedDate];
friends,I am getting a date based on the calculation I have done below
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *expectedDate = [gregorian dateByAddingComponents:components toDate:startDate options:0];
NSTimeInterval timeZoneOffset = -[[NSTimeZone systemTimeZone] secondsFromGMTForDate:expectedDate];
NSDate *localDate = [expectedDate dateByAddingTimeInterval:(timeZoneOffset)];
NSString *date = [dateFormatter stringFromDate:localDate];
But the date goes wrong when the daylightsaving is in effect,and also the timeZoneOffset changes when the daylightsaving is in effect, but I want the same date irrespective of whether the daylight saving is in effect or no..
So friends,how shall I handle this situation,please help.
Regards
Ranjit
You don't need to take care of daylight saving time yourself, the "dateFormatter" does that automatically for you. Usually you only need a NSDate object in UTC (GMT+0) time and "dateFormatter", which also has a time zone, will display that time in its own time zone.
NSCalendar and NSDateFormatter have time zone settings. NSDate is just a point in time relative to GMT+0.
Example:
"expectedDate" is January 1st 4am (GMT+0)
"dateFormatter" has time zone GMT+2 (e.g. Europe/Berlin) set, then it will output "January 1st 6am" because of its own time zone when converting "expectedDate" into a string.
So basically you just need to ensure that "startDate" is correct and that "gregorian" and "dateFormatter" use the correct time zone. By default they use the system time zone, which seems to be the one you want to use. So you need only these lines (and startDate has to be correct):
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *expectedDate = [gregorian dateByAddingComponents:components toDate:startDate options:0];
NSString *date = [dateFormatter stringFromDate:expectedDate];
If that doesn't work, please post more code about how startDate and dateFormatter are generated.
James, try this
//To Fix DaylightSaving, 1 hr added to startDate.
NSTimeInterval secondsInOneHour = 1 * 60 * 60;
NSDate *expectedDST = [startDate dateByAddingTimeInterval:secondsInOneHour];
NSDate *expectedDate = [gregorian dateByAddingComponents:components toDate:expectedDST options:0];
NSTimeInterval timeZoneOffset = -[[NSTimeZone systemTimeZone] secondsFromGMTForDate:expectedDate];
NSDate *localDate = [expectedDate dateByAddingTimeInterval:timeZoneOffset];
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.
I have been racking my brains on this one looking for a quick solution.
I need to fire off a NSTime at a specific time based on the current time in a specific time zone.
For example, I get the current time in PST:
NSDate *now = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"HH:mm:ss";
NSCalendar * cal = [[NSCalendar alloc] initWithCalendarIdentifier: NSGregorianCalendar];
[cal setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"PST"]];
NSDateComponents * comps = [cal components:NSHourCalendarUnit fromDate:now];
I see that the time is 2 (14) getting [comps hour] and I need to fire a timer at 2:30PM (14:30) on that day. I need help converting it back and doing the math to say how long it is before the timer fires. I will be setting up several different timers based on the current time. While I am looking at the time in PST I know that the timers and setting of the time is done in GMT. That's another twist...
Thanks in advance...
I solved the problem myself.. But thanks for the tips...
if ([date earlierDate:newDate] == date) // it is before 7AM... fire at 7AM
and so on....