All,
This seems like such a simple thing, but I cannot find* the right method to create a UIDatePicker, in time mode, and have it initialized to a specific time. I don't want date -- just time (think alarm clock). I have created a NSDate object:
NSDate * date = [[NSDate alloc] initWithTimeIntervalSinceReferenceDate: (NSTimeInterval) delta];
pickerView = [[UIDatePicker alloc] init]; // which should be 'now' right?
pickerView.datePickerMode = UIDatePickerModeTime; // which creates just the clock
[pickerView setDate:date];
and in the first line, the interval (delta) is zero. It displays 7:00PM.
This has gotta be so simple that I'm missing it, but I can't find the right way -- anyone?
Thank you in advance!
:bp:
*yes, I have looked, but apparently not in the correct places :(
Take the time zone into account. You will get 0AM only if you are at UTC.
Thank you dkk -- I appreciate your help. The real answer was to not use a DatePicker, but to use a PickerView (w/o the date). That made things simpler and do-able.
Thanks again.
NSDate *date = [NSDate date];
date = [[NSCalendar autoupdatingCurrentCalendar] dateFromComponents:[[NSCalendar autoupdatingCurrentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:date]];
date = [date dateByAddingTimeInterval:60 * 60 * 21];
pickerView.date = date;
The steps here with the date are
initialise date with the current date
get the date at midnight
add a time interval to the date (60 seconds * 60 minutes * hour). In this case 21 = 9pm
This works for UIDatePicker with datePickerMode of UIDatePickerModeTime & UIDatePickerModeCountDownTimer
Related
I'm getting a curious issue when creating NSDates using dateWithTimeIntervalSince1970 on a simulator versus an iPhone device. I am simply translating an ISO8601 timestamp from an NSDate to milliseconds and then back to a NSDate.
NSDateFormatter *iso8601Formatter = [[NSDateFormatter alloc] init];
iso8601Formatter.dateFormat = TSMISO8601FormatString; // "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
NSDate startDate = [iso8601Formatter dateFromString: #"2014-03-19T09:46:00-06:00"];
long startTimeMilliseconds = [startDate timeIntervalSince1970] * 1000;
startDate = [NSDate dateWithTimeIntervalSince1970:(startTimeMilliseconds / 1000)];
When I run this on the simulator, I get the same date back but when I run it on my iPhone, I get back this. I'm really confused as to why I'm getting back a wildly different day
1970-01-25 20:31:23 +0000 // iPhone device results
I have checked to make sure that my timezone, date, and time format are the same on both just to make sure that this isn't the issue. And both are running iOS 7.1. I have also attempted to set both the locale and timezone for the NSDateFormatter without any success.
Any help would be appreciated
This:
long startTimeMilliseconds = [startDate timeIntervalSince1970] * 1000;
Should Be:
double startTimeMilliseconds = [startDate timeIntervalSince1970] * 1000;
Here's why,
The maximum long can be found with LONG_MAX and it will log:
2147483647
Your current time interval is:
1395243960000.000000
Long can't go big enough.
I am trying to find how many milliseconds into the current day we are. I can't find a method to return the time in milliseconds ignoring date, so I figured I could calculate it off of the value returned by timeIntervalSince 1970 method.
I did this:
NSLog(#"%f", [[NSDate date] timeIntervalSince1970]);
2013-05-21 16:29:09.453 TestApp[13951:c07] 1369171749.453490
Now my assumption is that, since there are 86,400 seconds in a day I could divide this value by 86400 and get how many days have elapsed since 1970. Doing this gives me 15846.8952483 days. Now, if my assumption holds, I am 89.52483% through the current day. So multiple 24 hours by 86.52659% would give me a current time of the 21.4859592 hour or about 09:29 PM. As you can see from my NSLog this is about 5 hours from the real time, but I believe the interval returned is GMT so this would be 5 hours ahead of my time zone.
So I figured, well what the heck, I'll just roll with it and see what happens.
I cut off the decimal places by doing:
float timeSince1970 = [[NSDate date] timeIntervalSince1970]/86400.0;
timeSince1970 = timeSince1970 - (int)timeSince1970
Then calculate the milliseconds that have taken place thus far today:
int timeNow = timeSince1970 * 86400000;
NSLog(#"%i", timeNow);
2013-05-21 16:33:37.793 TestApp[14009:c07] 77625000
Then I convert the milliseconds (which still seem appropriate) to NSDate:
NSString *timeString = [NSString stringWithFormat:#"%d", timeNow];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"A"]
NSDate *dateNow = [dateFormatter dateFromString:timeString];
NSLog(#"%#", dateNow);
2013-05-21 16:29:09.455 TestApp[13951:c07] 2000-01-02 03:29:00 +0000
And there is my problem. Rather than returning a 2000-01-01 date with some hours and minutes attached, it is returning a 2000-01-02 date. Why!?
EDIT
I got it working by "removing" the extra 5 hours I noted in the above with:
int timeNow = (timeSince1970 * 86400000) - (5 * 60 * 60 * 1000);
I don't understand why this is necessary though. If someone can explain I'd greatly appreciate it.
EDIT 2
Perhaps I should be asking a more elementary question about how to accomplish the task I'm trying to accomplish. I care about times (for example, 4pm is important but I could care less about the date). I've been storing these in NSDates created by:
[dateFormatter setDateFormat:#"hh:mm a"];
[dateFormatter dateFromString#"04:00 PM"];
All this seems to be going fine. Now I want to compare current time to my saved time and find out if it is NSOrderedAscending or NSOrderedDescending and respond accordingly. Is there a better way to be accomplishing this?
You need to use NSCalendar to generate NSDateComponents based on right now, then set the starting hour, minute, and second all to 0. That will give you the beginning of today. Then you can use NSDate's -timeIntervalSinceNow method to get back the time elapsed between now and your start date.
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
// BUILD UP NSDate OBJECT FOR THE BEGINNING OF TODAY
NSDateComponents *comps = [cal components: (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate: now];
comps.hour = 0;
comps.minute = 0;
comps.second = 0;
// USE CALENDAR TO GENERATE NEW DATE FROM COMPONENTS
NSDate *startOfToday = [cal dateFromComponents: comps];
// YOUR ELAPSED TIME
NSLog(#"%f", [startOfToday timeIntervalSinceNow]);
Edit 1
If you're just looking to compare some NSDateObjects you can see if the time interval between then and now is negative. If so, that date is in the past.
NSDate *saveDate = [modelObject lastSaveDate];
NSTimeInterval difference = [saveDate timeIntervalSinceNow];
BOOL firstDateIsInPast = difference < 0;
if (firstDateIsInPast) {
NSLog(#"Save date is in the past");
}
You could also use compare:.
NSDate* then = [NSDate distantPast];
NSDate* now = [NSDate date];
[then compare: now]; // NSOrderedAscending
The part of your question that says that you want to calculate "how many milliseconds into the current day we are" and then "4pm is important but I could care less about the date" makes it not answerable.
This is because "today" there could have been a time change, which changes the number of milliseconds since midnight (by adding or subtracting an hour, for instance, or a leap second at the end of a year, etc....) and if you don't have the date, you can't determine the number of milliseconds accurately.
Now, to address your edited question: If we assume today's date, then you need to use the time that you have stored and combine it with today's date to get a "specific point in time" which you can compare to the current date and time:
NSString *storedTime = #"04:00 PM";
// Use your current calendar
NSCalendar *cal = [NSCalendar currentCalendar];
// Create a date from the stored time
NSDateFormatter *dateFormatter = [NSDateFormatter new];
[dateFormatter setDateFormat:#"hh:mm a"];
NSDate *storedDate = [dateFormatter dateFromString:storedTime];
// Break it up into its components (ie hours and minutes)
NSDateComponents *storedDateComps = [cal components:NSHourCalendarUnit | NSMinuteCalendarUnit
fromDate:storedDate];
// Now we get the current date/time:
NSDate *currentDateAndTime = [NSDate date];
// Break it up into its components (the date portions)
NSDateComponents *todayComps = [cal components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:currentDateAndTime];
// Combine with your stored time
todayComps.hour = storedDateComps.hour;
todayComps.minute = storedDateComps.minute;
// Create a date from the comps.
// This will give us today's date, with the time that was stored
NSDate *currentDateWithStoredTime = [cal dateFromComponents:todayComps];
// Now, we have the current date and the stored value as a date, so it is simply a matter of comparing them:
NSComparisonResult result = [currentDateAndTime compare:currentDateWithStoredTime];
it is returning a 2000-01-02 date. Why!?
Because your dateFormatter uses the current system locale's timezone.
If you insert ...
dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
... your date formatter will interpret the string correctly. But why not creating the date directly:
NSDate *dateNow = [NSDate dateWithTimeIntervalSinceReferenceDate:timeNow];
Here's my code:
picker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0,40,0,0)];
picker.datePickerMode = UIDatePickerModeDateAndTime;
picker.minuteInterval = 5;
picker.minimumDate = [NSDate date];
Ok, It's working fine until here. (Image: http://img29.imageshack.us/img29/8277/snap1r.png)
Days that are past in the DatePicker were all grayed out. It can't be selected.
And minute Intervals are 5.
But now when I click any row that were already Grayed out. The date of DatePicker returns time of this moment.
For Example:I cliked "9" on the DatePicker (It's already past time)
And the system time now is
22:27:57
and the Date of DatePicker returns: (Image: http://img42.imageshack.us/img42/2760/nslog.png)
2012-04-08 22:27
Because my minute interval is 5 minute, so I don't hope the picker returns the value that can't be divided by 5, this will cause my program crash.
Is this a Bug? or it's just my problem?
thanks!
------To inspector g (Sorry my English isn't very good)
Because the minuteInterval of Datepicker is 5. So the return value of DatePicker's date only returns minute that can divded by 5 (etc. 0, 5 , 10 , 15 .....)
and also I have the property minimumDate set to [NSDate date], so that users can't select the date in past.
but now of user click a row that was in past (grayed out), the DatePicker's date return the time at that moment.
so the minute of date could be any value (0~60) but not I wished ( 0 , 5 , 10 , 15....)
I've tried my best to explain >"< please forgive.
To Inspector g.
Thanks for your code, I suddenly realized there's a nice way to solve my problem.
But I dunno why, there are some problems if I use your code. (I guess it's about timeZone)
But I follow your logic and re-write a code, I'll share with you:
unsigned unitFlags_ = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit;
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comps_ = [gregorian components:unitFlags_ fromDate:[jRemindPicker date]];
NSInteger remainder = [comps_ minute] % 5;
NSLog(#"%i-%i-%i %i:%i", comps_.year, comps_.month, comps_.day, comps_.hour, comps_.minute);
if ( remainder ) {
/* My Own code /*
} else {
/* My Own Code /*
}
[gregorian release];
Your description of the problem with selecting a date/time is a little unclear, so perhaps you can clarify? Provide a short screencast?
In any event, it sounds like you cannot select a date before today, so your error is in this line:
picker.minimumDate = [NSDate date];
You are setting the minimum selectable date to the current date and time (as that's what [NSDate date] returns.
Remove that line and you should be able to select whatever date/time you wish.
EDIT
If the problem is that you can't select a date in the future, try setting:
picker.maximumDate = [NSDate distantFuture];
Using your existing minimum and this new maximum, the range of selectable dates will be set to somewhere between today and a very long time after today.
SECOND EDIT
Thanks for clarifying! I see the problem now. When you receive the callback from the user changing the date, you have to round up or down appropriately. You can then use the rounded time at that point, or manually set the picker date/time to the rounded value via setDate: animated:
For example:
-(IBAction) pickerValueChanged:(id)selector_
{
UIDatePicker* picker = (UIDatePicker*) selector_;
// get the minutes from the picker
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* components = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit) fromDate:picker.date];
NSInteger minutes = [components minute];
// check if the minutes should be rounded
NSInteger remainder = minutes % 5;
if(remainder)
{
minutes += 5 - remainder;
[components setMinute:minutes];
picker.date = [calendar dateFromComponents:components];
}
// now picker.date is "safe" to use!
}
I want to present a date to the user of my app as "Today", "Yesterday" or as a formatted date (i.e. 27/05/2011). Is there a quick way to get "Today" or "Yesterday" based on a given NSDate? If not I can write the code myself, I am just curious if I am overlooking some simpler way than working out remaining hours manually.
If you just want to present date to your user, there is an option in NSDateFormatter right for that.
- (void)setDoesRelativeDateFormatting:(BOOL)b
Take a look at documentation for more information.
Check out this similar question: Compare NSDate for Today or Yesterday.
You make NSDate objects from today and yesterday, and then compare the first 10 characters of their description to the NSDate you're unsure of.
From the Date and Time Programming Guide:
NSTimeInterval secondsPerDay = 24 * 60 * 60;
NSDate *today = [[NSDate alloc] init];
NSDate *tomorrow, *yesterday;
tomorrow = [today dateByAddingTimeInterval: secondsPerDay];
yesterday = [today dateByAddingTimeInterval: -secondsPerDay];
[today release];
How to get/set the hours and minutes via code from a UIDatePicker in UIDatePickerModeCountDownTimer mode?
The situation:
I have an interface in that a user selects just hours and minutes. Then, he saves the information (so, I have to get the hours and minutes from UIDatePicker via code to save in a DB).
When the user is editing the information saved previously, I want to start the interface with the saved hours/minutes (so, I have to set the UIDatePicker hours and minutes via code with values from DB).
How do I do that with the UIDatePicker in UIDatePickerModeCountDownTimer mode?
Thanks in advance.
You have to use the countDownDuration property in UIDatePicker when the date picker mode is set to UIDatePickerModeCountDownTimer.
The countdown duration is in seconds, so you can calculate that from a NSDate as follows (to test it just drop it into the viewDidLoad of any UIViewController):
// Create a new date with the current time
NSDate *date = [NSDate new];
// Split up the date components
NSDateComponents *time = [[NSCalendar currentCalendar]
components:NSHourCalendarUnit | NSMinuteCalendarUnit
fromDate:date];
NSInteger seconds = ([time hour] * 60 * 60) + ([time minute] * 60);
UIDatePicker *picker = [UIDatePicker new];
[picker setDatePickerMode:UIDatePickerModeCountDownTimer];
[picker setCountDownDuration:seconds];
[[self view] addSubview:picker];
So if the current time is 17:28, the UIDatePicker will show "17 hours 28 mins". Simly replace the NSDate with the one you get from the DB and you should be sorted :)