Error when convert float to datatime - objective-c

I have this command that is being called each second in background mode, Every time he is called I add +1 to my variable of type float, and convert to date format:
xis = (xis + 1) / 000001;
//The Format which you want as output
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
dateFormat.dateFormat = #"ss:mm:hh";
[dateFormat setTimeZone:[NSTimeZone systemTimeZone]];
//The Format in which your dateTime currently is
NSDateFormatter *dateFormat1 = [[NSDateFormatter alloc] init];
dateFormat1.dateFormat = #"hh.mm";
[dateFormat1 setTimeZone:[NSTimeZone systemTimeZone]];
NSString *timeStr = [NSString stringWithFormat:#"%.2f",xis];
NSDate *dates = [dateFormat1 dateFromString:timeStr];
NSLog(#"Time: %#", [dateFormat stringFromDate:dates]);
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
recordTime.text = [NSString stringWithFormat:#"%#",[dateFormat stringFromDate:dates]];
}];
But this code has a problem when the time comes 00:00:12, something goes wrong and the time is the value (null), which may be causing this and how can I solve?

There are two issues:
I would advise against using the NSTimer routine to keep track of elapsed time yourself. Timers may not be called with the frequency you expect. Also, if the user suspended the app and came back to it, you don't really want to try to keep this timer going while the app is no longer in the foreground. In short, you want to decouple the updating of the UI from the calculation of the elapsed time string representation.
So, instead, one should capture the "start time" and then have the routine get the current time, compare that to the "start time" and calculates the string representation of this elapsed time. But notably, there is no incrementing of variables for seconds elapsed, but rather one should rely on the system time of the device.
Your formatting problem stems from the awkward conversion of your numeric counter to a date string. The problem was complicated by the fact that the formatting string that was backwards, ss:mm:hh.
First (and to my above point), I'd probably calculate the time elapsed in seconds, by capturing the start time up front and store it in a CFAbsoluteTime property:
self.start = CFAbsoluteTimeGetCurrent();
And, if you really wanted to use NSDateFormatter, instead of using it to interpret a numeric value, I would only use it for converting to and from NSDate objects. You could, for example, get the NSDate for 00:00:00, use dateByAddingTimeInterval to add the elapsed time to the date, and then use the formatter to get the output string:
// calculate the time elapsed in seconds
CFTimeInterval elapsed = CFAbsoluteTimeGetCurrent() - self.start;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"HH:mm:ss";
NSDate *start = [formatter dateFromString:#"00:00:00"];
NSDate *end = [start dateByAddingTimeInterval:elapsed];
NSString *elapsedString = [formatter stringFromDate:end];
Having said that, I'd probably favor a couple of different approaches. One is to just calculate hours, minutes, and seconds manually:
// calculate the time elapsed in seconds
CFTimeInterval elapsed = CFAbsoluteTimeGetCurrent() - self.start;
// convert this to hours, minutes, and seconds
double seconds;
double minutes;
double hours;
seconds = modf(elapsed / 60.0, &minutes) * 60.0;
minutes = modf(minutes / 60.0, &hours) * 60.0;
// create format string
NSString *elapsedString = [NSString stringWithFormat:#"%02.0f:%02.0f:%04.1f", hours, minutes, seconds];
Or a completely different approach would be to use NSCalendar. In this scenario, one might have a NSDate property that you initialize with the start time:
self.startDate = [NSDate date];
And then you could do something like:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
NSDateComponents *components = [calendar components:NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:self.startDate toDate:now options:0];
NSString *elapsedString = [NSString stringWithFormat:#"%02ld:%02ld:%02ld", (long)components.hour, (long)components.minute, (long)components.second];
Just a few approaches. But I'd advise against manually incrementing your counter manually, and I might suggest one of these latter techniques.

Related

How can I handle this European-style timestamp?

I’m trying to check through thousands of lines in video subtitle files (in .srt format) and searched the internet for days on end for a solution, but to no avail. The subs contain in/out timestamps as shown in the following example:
61
00:08:35,504 --> 00:08:38,629
Do you know where he left the car keys?
in hours, minutes, seconds and milliseconds (notice the European-style comma before the millisecond part, representing the decimal point). What I plan to do is parse the timestamp into its two components and check the difference between them, since many are faulty. I built a simple test function to handle the plain hh:mm:ss part which works well:
-(IBAction)checkSubLength:(id)sender
{
NSString *inStr = #"10:10:45";
NSString *outStr = #"10:20:57";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"hh:mm:ss"];
NSDate *inTime = [dateFormatter dateFromString:inStr];
NSDate *outTime = [dateFormatter dateFromString:outStr];
NSTimeInterval distanceBetweenDates = [outTime timeIntervalSinceDate:inTime];
NSLog(#"time difference:%.3f", distanceBetweenDates);
}
However, I just can’t get the fractional part to display no matter what I try. How can I modify/change my code do that? Any help much appreciated.
You need to specify the millis in the format string:
NSString *inStr = #"10:10:45,111";
NSString *outStr = #"10:20:57,222";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"hh:mm:ss,SSS"];
NSDate *inTime = [dateFormatter dateFromString:inStr];
NSDate *outTime = [dateFormatter dateFromString:outStr];
NSTimeInterval distanceBetweenDates = [outTime timeIntervalSinceDate:inTime];
NSLog(#"time difference:%.3f", distanceBetweenDates);
which then prints
time difference:612.111
as expected

Problems formatting dates

Here is the set up, I have a JSON feed I am using and I want to find the difference between two specific dates called posted_date and planned_expiration_date. They are in an odd format I so I thought I could truncate them down to just the date.I could then use NSTimeInterval to find the difference in seconds.
// Time Interval Left
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
NSString *startDate = [firstPerson objectForKey:#"posted_date"];
NSString *endDate = [firstPerson objectForKey:#"planned_expiration_date"];
//Ammend the strings to YYYY-MM-DD
[formatter setDateFormat:#"yyyy-mm-dd"];
int newlength = 9;
NSDate *startDateAmmended =[formatter dateFromString:[startDate substringFromIndex:newlength]];
NSDate *endDateAmmended = [formatter dateFromString:[endDate substringFromIndex:newlength]];
Here is the bit I'm not too sure about. The date appears something like this "2013-06-07T13:40:01Z" straight from the feed. I don't know how to deal with the T and Z chars in the date formatter method so I truncate the string with substringFromIndex to make it 10 chars and then attempted the following code.
//Difference in Date
NSTimeInterval *startDifference = [startDateAmmended timeIntervalSinceNow];
NSTimeInterval *endDifference = [endDateAmmended timeIntervalSinceNow];
NSTimeInterval timeDifferenceInSeconds = startDifference - endDifference;
I get the following error, .../JSONParser/ViewController.m:52:21: Initializing 'NSTimeInterval *' (aka 'double *') with an expression of incompatible type 'NSTimeInterval' (aka 'double') at the first two calls to NSTimeInterval.
I am sure I'm going wrong in a few places and I'm sure this isn't the easiest method of doing it. Could anyone recommend how I would fix this issue or an easier way to go about getting the differences between dates?
Your error comes from your lines that say:
NSTimeInterval *startDifference = [startDateAmmended timeIntervalSinceNow];
NSTimeInterval *endDifference = [endDateAmmended timeIntervalSinceNow];
They should be:
NSTimeInterval startDifference = [startDateAmmended timeIntervalSinceNow];
NSTimeInterval endDifference = [endDateAmmended timeIntervalSinceNow];
Or, more simply, don't define those two difference variables at all, and just use:
NSTimeInterval timeDifferenceInSeconds = [endDateAmmended timeIntervalSinceDate:startDateAmmended];
To calculate the difference between two ISO 8601 / RFC 3339 date strings, you can do:
NSDate *startDate = [self dateFromISO8601String:#"2013-06-01T16:27:35Z"];
NSDate *endDate = [self dateFromISO8601String:#"2013-06-07T13:40:01Z"];
NSTimeInterval elapsed = [endDate timeIntervalSinceDate:startDate];
NSLog(#"Time elapsed (in seconds) is %.0f", elapsed);
where dateFromISO8601String is defined as:
- (NSDate *)dateFromISO8601String:(NSString *)string
{
static NSDateFormatter *formatter = nil;
if (formatter == nil)
{
formatter = [[NSDateFormatter alloc] init];
NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
formatter.locale = enUSPOSIXLocale;
formatter.dateFormat = #"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'";
formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
}
return [formatter dateFromString:string];
}
You can get the difference in seconds between two NSDate objects like this:
double difference = [startDateAmmended timeIntervalSinceDate:endDateAmmended];
Note that with the substring operation you don't have the time, only the date, so the difference will be in seconds but with steps of whole days.

current Date and Time - NSDate

I need to display the current Date and Time.
I have used ;
NSDate *currentDateNTime = [NSDate date];
I want to have the current date and time (Should display the system time and not GMT time).
The output should be in a NSDate format and not NSString.
for example;
NSDate *currentDateNTime = [NSDate date];
// Do the processing....
NSDate *nowDateAndTime = .....; // Output should be a NSDate and not a NSString
Since all NSDate is GMT referred, you probably want this:
(don'f forget that the nowDate won't be the actual current system date-time, but it's "shifted", so if you will generate NSString using NSDateFormatter, you will see a wrong date)
NSDate* currentDate = [NSDate date];
NSTimeZone* currentTimeZone = [NSTimeZone timeZoneWithAbbreviation:#"GMT"];
NSTimeZone* nowTimeZone = [NSTimeZone systemTimeZone];
NSInteger currentGMTOffset = [currentTimeZone secondsFromGMTForDate:currentDate];
NSInteger nowGMTOffset = [nowTimeZone secondsFromGMTForDate:currentDate];
NSTimeInterval interval = nowGMTOffset - currentGMTOffset;
NSDate* nowDate = [[NSDate alloc] initWithTimeInterval:interval sinceDate:currentDate];
Every moment in time is the same moment in time everywhere around the world —- it is just expressed as different clock times in different timezones. Therefore, you can't change the date to some other date that represents the time in your timezone; you must use an NSDateFormatter that you feed with the timezone you are in. The resulting string is the moment in time expressed in the clock time of your position.
Do all needed calculations in GMT, and just use a formatter for displaying.
Worth reading
Does [NSDate date] return the local date and time?
Some useful resources for anyone coming to this more recently:
Apple date and time programming guide do read it if you're doing anything serious with dates and times.
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/DatesAndTimes/DatesAndTimes.html#//apple_ref/doc/uid/10000039i?language=objc
Useful category on NSDate with lots of utilities does allow a ~new~ date to be generated based on an existing date.
https://github.com/erica/NSDate-Extensions
There's also a swift version of the category
https://github.com/erica/SwiftDates
You need an NSDateFormatter and call stringFromDate this method to get a string of your date.
NSDateFormatter *dateformater = [[NSDateFormatter alloc] init];
[dateformater setDateFormat:#"yyyyMMdd,HH:mm"];
NSString *str = [dateformater stringFromDate: currentDateNTime];
use this method
-(NSDate *)convertDateToDate:(NSDate *) date
{
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
NSDate *nowDate = [[[NSDate alloc] init] autorelease];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[formatter setDateFormat:#"yyyy-MM-d H:m:s"];
NSString * strdate = [formatter stringFromDate:date];
nowDate = [formatter dateFromString:strdate];
return nowDate;
}
this may return you what you want.
i hope you this may help you.

Formatting seconds into hh:ii:ss

I have app that is a basic timer. It tracks the number of seconds the app has run. I want to convert it so the seconds (NSUInteger) are displayed like: 00:00:12 (hh:mm:ss). So I've read this post:
NSNumber of seconds to Hours, minutes, seconds
From which I wrote this code:
NSDate *date = [NSDate dateWithTimeIntervalSince1970:[[self meeting] elapsedSeconds]];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"hh:mm:ss"];
It works fine, but it starts out with 04:00:00. I'm not sure why. I also tried doing something like:
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:[[self meeting] elapsedSeconds] * -1];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"hh:mm:ss"];
Thinking that it would display the counter correctly, but it does a wierd 01:23:00, then just flops to 04:00:00 and stays there for the rest of the time.
MS
This is similar to a previous answer about formatting time but doesn't require a date formatter because we aren't dealing with dates any more.
If you have the number of seconds stored as an integer, you can work out the individual time components yourself:
NSUInteger h = elapsedSeconds / 3600;
NSUInteger m = (elapsedSeconds / 60) % 60;
NSUInteger s = elapsedSeconds % 60;
NSString *formattedTime = [NSString stringWithFormat:#"%u:%02u:%02u", h, m, s];
While there are easier ways of doing this (#dreamlax has a very good way), let me explain what is wrong with your example and let's get it working:
First, the reason that it is showing 04:00:00 (well, it is probably actually showing 04:00:12) is because it is converting the time from UTC/GMT to your local time. To fix this, you need to add the following line:
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
Then, it will no longer show 04:00:12 because it doesn't convert the timezone. Unfortunately, it will now show 12:00:12 instead of 00:00:12 because it is midnight. In order to fix that, have it convert the string to 24 hour time instead by using the HH formatter instead of hh:
[formatter setDateFormat:#"HH:mm:ss"];
Keep in mind that since this was designed to work with times, that it will not work for more than 24 hours (because it will "roll over" to midnight again).
The full code would be:
NSDate *date = [NSDate dateWithTimeIntervalSince1970:[[self meeting] elapsedSeconds]];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"HH:mm:ss"];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSLog(#"%#", [formatter stringFromDate:date]);
// Results: 00:00:12

What's the best/easiest way to compare two times in Objective-C?

I've got a string representation of a time, like "11:13 AM." This was produced using an NSDateFormatter and the stringFromDate: method.
I'd like to compare this time to the current time, but when I use the dateFromString: method to turn the string back into a date, a year, month and day are added - which I don't want. I just need to know if right now is < or > the time stored in the string.
What's going to be the best way to handle that? Thanks in advance for your help.
Instead of using the string representation, use the NSDate you got from the picker. You can convert that hour/min/sec using NSDateComponents, then also convert [NSDate date] to NSDateComponents. Compare the hours/minutes/seconds of the two sets of components.
EDIT -- use a utility function for things like this that converts the hr/min/sec components of NSDate into a secondsOfTheDay (seconds since midnight).
You can directly use two time of day values since they are both seconds since midnight. Simple integers can be easily compared and stored and manipulated. You don't have to use NSDate all the time.
//----------------------------------------------------------------------------
// extracts hour/minutes/seconds from NSDate, converts to seconds since midnight
//----------------------------------------------------------------------------
unsigned secondOfTheDay( NSDate* time )
{
NSCalendar* curCalendar = [NSCalendar currentCalendar];
const unsigned units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents* comps = [curCalendar components:units fromDate:time];
int hour = [comps hour];
int min = [comps minute];
int sec = [comps second];
return ((hour * 60) + min) * 60 + sec;
}
If I understand the problem correctly, you’re using the dateFromString: method of NSDateFormatter. This is giving you the correct time, but with a default date of January 1, 1970, which is useless to compare against the current date/time.
This is easy to solve. Use setDefaultDate: to set the default date to today.
NSDate *now = [NSDate date];
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setDateFormat:#"hh:mm a"];
[formatter setDefaultDate:now];
NSDate *theDate = [formatter dateFromString:#"11:13 AM"];
NSComparisonResult theResult = [theDate compare:now];
Can you reuse the string formatter that you used to create the string? So, let's say you created the string like this:
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init];
[formatter setDateFormat:#"HH:mm a"];
NSString *dateAsString = [formatter stringFromDate:[NSDate date]];
You can get an NSDate like this:
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init];
[formatter setDateFormat:#"HH:mm a"];
NSDate *date = [formatter dateFromString:dateAsString];
The day, month, year and timezone information will not be kept, but you'll have an NSDate object with the values of 1/1/1970 and GMT for the timezone offset.
At this point you can use the compare: (which is typically reserved for sorting operations) or the laterDate: or earlierDate: methods.
Be careful using NSDateFormatter like this, as you may run into issues with internationalization.
If you need to add information about the current date to the date you get from dateFromString:, such as the month day and year, you'll need to use NSCalendar's dateByAddingComponents:toDate:options: method.
If the string was originally created from an NSDate, then you'll want to use that original NSDate to compare against [NSDate date] using NSDate's compare: method (or some variant, such as earlierDate: or laterDate:).
You should use 24-hour based NSDateFormatter and compare as strings ("09:00am" > "08:00pm", but "09:00" < "20:00") . But in general it is right to operate with NSDate instances instead of strings