I am trying to create an app that calculates the time difference and the amount is multiplied by an amount in money. It is targeted to calculate in R$ (brazilian real) the amount that someone will have to pay for using a service during the time calculated by the app.
HereĀ“s is my code:
- (IBAction)encerrar:(id)sender {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"HH:mm";
NSString *temp = inicio.text;
NSDate *then = [dateFormatter dateFromString:temp];
NSDate *now = [NSDate date];
NSTimeInterval timeInterval = [now timeIntervalSinceDate:then];
NSString *ext = [dateFormatter stringFromDate:now];
fim.text = ext;
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString = [dateFormatter stringFromDate:timerDate];
duracao.text = timeString;
double timeIntervalInHours = (timeInterval / 3600.0) * 5;
NSString *vTotal = [[NSString alloc] initWithFormat:#"R$ %.2f", fecha];
NSLog(#"%.2f", timeIntervalInHours);
vlrTotal.text = vTotal;
}
The fact is that when we click on Calculate button, and if the duracao (duration) is equal to 1h it gives me the correct amount which is R$ 5,00. But when the duration is equal to 30mins or other value different from exact 1h, it gives the wrong amount.
I.E.: 1h should be R$ 5,00; while 1:30h should be R$ 7,50, but shows me R$ 6,50.
So, anyone could help me on this???
Thanks in advance!!!
timeInterval is the amount of time in seconds, so if you want it in hours and fractions of an hour just do this:
double timeIntervalInHours = timeInterval / 3600.0;
and then multiple timeIntervalInHours times the price/hour to get the cost.
EDIT
Based on our chat, I would create a button with "iniciar" (start) as the title. When they press that button, I would store the current time and change the title to "encerrar" (stop). (I hope that my translations are correct, lol) Then the button action would look something like this:
// self.startTime is a NSDate.
- (IBAction)iniciar_encerrar:(UIButton *)sender {
if ([sender.titleLabel.text isEqualToString:#"iniciar"]) {
// We are starting the time
if (self.startTime != nil) {
return;
}
self.startTime = [NSDate date];
[sender setTitle:#"encerrar" forState:UIControlStateNormal];
} else {
// We are stopping the time
NSDate *currentTime = [NSDate date];
NSTimeInterval elapsedTimeInSeconds = [currentTime timeIntervalSinceDate:self.startTime];
double cost = elapsedTimeInSeconds / 3600.0 * 5.0;
NSLog(#"%.2lf", cost);
// reset the button
self.startTime = nil;
[sender setTitle:#"iniciar" forState:UIControlStateNormal];
}
}
startTime is declared as follows:
In your .h file, along with the other declared properties, add:
#property (strong, nonatomic) NSDate *startTime;
In your .m file, add this at the top with the other ones:
#synthesize startTime;
In your viewDidUnload function (in your .m file) add this:
startTime = nil;
This just gives you a place to store the startTime date.
You're converting the time string HHmm to a float, so at 1.5 hours, you will have a float of 130 (1 hour 30 min). I can't follow your calculations from there. I think what you want is to have two formatters, one to get minutes, and one for hours, like so:
formatter.dateFormat = #"HH";
float hours = [[formatter stringFromDate:timerDate] intValue] * 1.0;
formatter.dateFormat = #"mm";
hours += [[formatter stringFromDate:timerDate] intValue]/60.0; //convert min to fractional hours and add
I would convert the amount $R5,00 from an hourly amount to an amount per second for better accuracy. 5/ 60 minutes / 60 seconds gives you .00388889 which you would multiply by (duration*1000) to give you your accurate result.
Related
This question already has answers here:
Calculating the number of days between two dates in Objective-C
(8 answers)
Closed 6 years ago.
Suppose:
1bhk flat 200rupee maintainance
2bhk flat 400rupee maintainance charges
Suppose 1 bhk user pays the amount in a given date.
But if user does not pay the amount in the given date then automatically add 20% extra charge on to the basic amount.
Is it possible to implement this in Objective C?
It's very simple bro. Following code will work for 1BHK user.
float oneBHKCharge=200;
float finalDue=0;
NSString *strDueDate = #"10-02-2017";
NSString *strPaidDate = #"10-02-2017";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSDate *dueDate = [dateFormatter dateFromString:strDueDate];
NSDate *paidDate = [dateFormatter dateFromString:strPaidDate];
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *components = [gregorianCalendar components:NSCalendarUnitDay
fromDate:dueDate
toDate:paidDate
options:0];
if (components.day > 0)
{
finalDue = oneBHKCharge + oneBHKCharge*0.2;
}
else
{
finalDue = oneBHKCharge;
}
NSLog(#"%f",finalDue);
Here the code I solved this topic. I stored in the NSUserdefaults the days that count as overdue. An did here the check
- (NSNumber *)invoiceOverDue
{
NSNumber *result;
NSInteger dueDays = [[NSUserDefaults standardUserDefaults] integerForKey:VPPayDue];
if ([[self dueTime] intValue] > dueDays)
{
result = [NSNumber numberWithBool:YES];
}
else {
result = [NSNumber numberWithBool:NO];
}
return result;
}
And here the part in witch I calculate the overdue time.
// DueTime calculation
-(NSNumber *)dueTime
{
// NSTimeInterval secondsPerDay = 24 * 60 * 60;
if ([[self invoiceStatus] intValue] > 1)
{
return [NSNumber numberWithInt:0];
}
else {
NSTimeInterval calculateTime = [[* Insert here the date of your invoice*] timeIntervalSinceNow];
//DLog(#"dueTime bevor / 86400 :%f", calculateTime);
calculateTime /= -86400;
//DLog(#"dueTime :%f", calculateTime);
int returnInt = [ConverterHelper numberRoundUp:calculateTime];
return [NSNumber numberWithInt:returnInt];
}
}
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.
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.
I'm trying to countdown from a NSDate and display it in hours and minutes. Like this: 1h:18min
At the moment my date is updating to a UILabel and counting down but displaying like this:
Here's the code I'm using. A startTimer method and a updateLabel method
- (void)startTimer {
// Set the date you want to count from
// convert date string to date then set to a label
NSDateFormatter *dateStringParser = [[NSDateFormatter alloc] init];
[dateStringParser setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.000Z"];
NSDate *date = [dateStringParser dateFromString:deadlineDate];
NSDateFormatter *labelFormatter = [[NSDateFormatter alloc] init];
[labelFormatter setDateFormat:#"HH-dd-MM-yyyy"];
NSDate *countdownDate = [[NSDate alloc] init];
countdownDate = date;
// Create a timer that fires every second repeatedly and save it in an ivar
NSTimer *timer = [[NSTimer alloc] init];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateLabel) userInfo:nil repeats:YES];
}
- (void)updateLabel {
// convert date string to date then set to a label
NSDateFormatter *dateStringParser = [[NSDateFormatter alloc] init];
[dateStringParser setDateFormat:#"yyyy-MM-dd'T'HH:mm:ss.000Z"];
NSDate *date = [dateStringParser dateFromString:deadlineDate];
NSDateFormatter *labelFormatter = [[NSDateFormatter alloc] init];
[labelFormatter setDateFormat:#"HH-dd-MM"];
NSTimeInterval timeInterval = [date timeIntervalSinceNow]; ///< Assuming this is in the future for now.
self.deadlineLbl.text = [NSString stringWithFormat:#"%f", timeInterval];
}
thanks for any help
- (NSString *)stringFromTimeInterval:(NSTimeInterval)interval
{
NSInteger ti = (NSInteger)interval;
NSInteger seconds = ti % 60;
NSInteger minutes = (ti / 60) % 60;
NSInteger hours = (ti / 3600);
return [NSString stringWithFormat:#"%02i:%02i:%02i", hours, minutes, seconds];
}
Since you use NSTimeInterval ,you are getting the time interval ,ie the difference, in seconds, to display it in hours and minutes you need to apply mathematics logic and convert it!
You many need a few loops to do it.
try this
Regards
i try to convert a value like "898.171813964844" into 00:17:02 (hh:mm:ss).
How can this be done in objective c?
Thanks for help!
Final solution:
NSNumber *time = [NSNumber numberWithDouble:([online_time doubleValue] - 3600)];
NSTimeInterval interval = [time doubleValue];
NSDate *online = [NSDate date];
online = [NSDate dateWithTimeIntervalSince1970:interval];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"HH:mm:ss"];
NSLog(#"result: %#", [dateFormatter stringFromDate:online]);
Assuming you are just interested in hours, minutes and seconds and that the input value is less or equal 86400 you could do something like this:
NSNumber *theDouble = [NSNumber numberWithDouble:898.171813964844];
int inputSeconds = [theDouble intValue];
int hours = inputSeconds / 3600;
int minutes = ( inputSeconds - hours * 3600 ) / 60;
int seconds = inputSeconds - hours * 3600 - minutes * 60;
NSString *theTime = [NSString stringWithFormat:#"%.2d:%.2d:%.2d", hours, minutes, seconds];
I know the answer has already been accepted, but here is my response using NSDateFormatter and taking into account timezone (to your timezone hours [eg. GMT+4] being unexpectedly added #Ben)
NSTimeInterval intervalValue = 898.171813964844;
NSDateFormatter *hmsFormatter = [[NSDateFormatter alloc] init];
[hmsFormatter setDateFormat:#"HH:mm:ss"];
[hmsFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSLog(#"formatted date: %#", [hmsFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceReferenceDate:intervalValue]]);
[side note] #phx: assuming 898.171813964844 is in seconds, this would represent 00:14:58 not 00:17:02.
Convert your NSNumber value to a NSTimeInterval with -doubleValue
Convert your NSTimeInterval value to a NSDate with +dateWithTimeIntervalSinceNow:
Convert your NSDate to a NSString with -descriptionWithCalendarFormat:timeZone:locale: