I'm working on a project which calculates a cost of calls from two different times entered by the user. I've parsed the data into the code as DateTime.
DateTime starttime = new DateTime(Convert.ToDateTime(cal1.SelectedDate).Year,Convert.ToDateTime(cal1.SelectedDate).Month,Convert.ToDateTime(cal1.SelectedDate).Day,
Convert.ToInt32(drpdwn1.SelectedValue),
Convert.ToInt32(drpdwn2.SelectedValue),
Convert.ToInt32(drpdwn3.SelectedValue));
DateTime endtime = new DateTime(Convert.ToDateTime(cal1.SelectedDate).Year, Convert.ToDateTime(cal1.SelectedDate).Month, Convert.ToDateTime(cal1.SelectedDate).Day,
Convert.ToInt32(drpdwn4.SelectedValue),
Convert.ToInt32(drpdwn5.SelectedValue),
Convert.ToInt32(drpdwn6.SelectedValue));
And subtracts the two to get a timespan.
TimeSpan duration3 = (endtime - starttime);
txtDisplay.Text = duration3.ToString();
Can someone help me find a way to multiply $0.35 to the timespan duration3?
Here is what I'm using right now but the textbox keeps displaying 0
double mins = duration3.Minutes;
double hrs = duration3.Hours;
double cost = ((hrs * 60) + mins) * 0.35;
txtCost.Text = cost.ToString();
//$0.35/min
// ((0.35*60)*hr + 0.35*min)
Possibly something like:
static decimal Foo(TimeSpan duration, decimal perMinuteRate)
=> ((decimal)duration.TotalMinutes) * perMinuteRate;
although note that TotalMinutes is a double, so this could have unexpected rounding if your duration is very fractional.
Better to do it this way, so you don't interfer with double precision errors:
public static decimal MultiplyPerMinute(TimeSpan a, decimal b)
{
return a.Ticks * b / TimeSpan.TicksPerMinute;
}
When you work with decimal, only double or float should scare you off in any possible operator. Decimal is a type made specificaly for digital, and precision durable operations.
As written, the question is not very clear. There are two questions really:
How to multiply a TimeSpan by a decimal?
Why is my TextBox always displaying zero?
Question 1 is not clear - it can be interpreted in many ways. From reading the posted code, comments and other answers it is possible to see that you are trying to calculate the "cost of a TimeSpan given the cost per minute". Why not ask this question?
But that isn't really your question - your posted code does indicate that you have an idea about how to calculate the "cost of a TimeSpan given the cost per minute", the problem is that your "textbox keeps displaying 0".
From the code posted, I don't know why this is. However, following some good debugging practices should fairly quickly help you narrow down the problem yourself.
See this link to a post by Eric Lippert that you should find useful:
How to debug small programs
No need to calculate the minutes yourself - and multiplying is easy:
TimeSpan ts = DateTime.Now - DateTime.Today;
var cost = ((int)ts.TotalMinutes) * 0.35m; // cost per minute, edited wrongly used 0.63m
I am int ing out the decimals of TotalMinutes to avoid billing for 23.2832s as well ;)
Related
I need to divide two TimeSpan.
I have one TimeSpan "worktime" and the other TimeSpan "productive"
What i want is to get as result of worktime/productive is a percentage. I need to get the "added value" (<- I think this is how it's called in english :)),
In .NET Core you can simply divide the TimeSpans. TimeSpan has a division operator.
This works:
var t1=TimeSpan.FromTicks(1000);
var t2=TimeSpan.FromTicks(100);
Console.WriteLine(t2/t1);
---------------------
0.1 ```
A Simple example:
DateTime d1 = DateTime.Parse("10:00:00");
DateTime d2 = DateTime.Parse("13:00:00");
TimeSpan t1 = d2 - d1; // three hours
TimeSpan t2 = new TimeSpan(0,15,0); // 15 minutes
Console.WriteLine(t1/t2);
This outputs: 12
see: https://onlinegdb.com/ImxwiWk37
var addedValue = (decimal)workTime.Ticks/productive.Ticks * 100;
The decimal cast is needed or the division will automatically round and you'll get very inaccurate percentages in certain cases.
I need to get the "added value"
By this, do you mean you want the percentage expressed as a percentage of the overall work time that was productive?
So if the total work time was 10 hours and the productive work time was 9 hours, the percentage of productive work time would be 90%?
If so, the answer is:
double percentage = double percentage = 100.0 - 100.0 * (worktime.Ticks - productive.Ticks) / worktime.Ticks;
I have this C# code which calculate compound interest plus principal amount every year.
static void CompoundInterest(double principal, double interestRate, double years, double annualCompound)
{
var total = 0.0;
for (int t = 1; t < years + 1; t++)
{
total = principal * Math.Pow((1 + interestRate / annualCompound),
(annualCompound * t));
Console.Write("Your Total for Year {0} "
+ "is {1}. \n", t, total);
}
}
When I tested it with
CompoundInterest(1000, 0.05, 3, 12);
and the output is
Your Total for Year 1 is 1051.161897881733.
Your Total for Year 2 is 1104.941335558327.
Your Total for Year 3 is 1161.4722313334678.
How should I round it accurately? Another question is Math.Pow uses double but in financial calculation, we need decimal. How do I fix this? Convert into decimal after Math.Pow?
I made some test by rounding first and converting to decimal and by converting to decimal and then rounding afterword. Both gave the same results.
But from the logic point of view, I would convert first than rounding after words. This way I will have better control of testing what is converted and what is rounded.
For converting there are different answers, but I found this method Convert.ToDecimal is supported by all .net frameworks and cores.
ex. decimal value = Convert.ToDecimal(double_value);
And then you decimal.Round, which some one has asked and got answer here Why does .NET use banker's rounding as default?
Just in case reference to Floating-point numeric types.
You can convert a double to a decimal directly if you'd like
decimal decimalTotal = (decimal)total;
As for rounding, there is a built-in function, Math.Round, that takes a variety of number formats. It has a overload to specify how many decimal points you want.
decimal roundedDecimal = Math.Round(decimalTotal, 2);
I am trying to convert a time represented in double, something like 23.40 which means 23 hours and 40 minutes, using the following method:
private TimeSpan DoubleToTimeSpan(double time)
{
double hour = Math.Floor(time);
double minute = (time - hour) * 100d;
TimeSpan ts = new TimeSpan((int)hour, (int)minute, 0);
return ts;
}
When testing it on some times, like 23.40 for example:
Console.WriteLine(DoubleToTimeSpan(23.40));
It shows 23:39:00, a whole minute has been stolen by the system! Where is my minute?
Note: I know about TimeSpan.FromHours, this doesn't help me because this method considers the minutes as percentage, so 23.40 is 23 hours and 40% of an hour, which is 23:24:00.
Since 0.4 cannot be exactly represented in the Double floating-point format, you get its nearest representation, which in the case of (23.4-23)*100 is probably something like 39.999999999999858. When you use (int), you truncate the fraction, leaving you with 39.
You need to round instead of truncate, so use (int)Math.Round(minute).
Alternatively, you can use the Decimal type, which can exactly represent decimal numbers like 23.40.
Try rounding it instead of int
private TimeSpan DoubleToTimeSpan(double time)
{
double hour = Math.Floor(time);
hour.Dump();
double minute = (time - hour) * 100d;
minute.Dump();
TimeSpan ts = new TimeSpan((int)hour, (int)Math.Round(minute), 0);
return ts;
}
If you do just (int)minute it will take the integer part of your double.
When you cast from a double to an int, it's truncating your value for minute -- thus your lost minute.
(time - hour) * 100d
Will evaluate to 39.999999999999858, and thus 39 when casting to int.
You've used Math.Floor for the hour, so use Math.Ceiling for the minute. It seems to work ok.
private static TimeSpan DoubleToTimeSpan(double time)
{
return new TimeSpan((int)Math.Floor(time), (int)Math.Ceiling((time - Math.Floor(time)) * 100d), 0);
}
Another option to use decimals. This will prevent precision loss.
decimal minute = ((decimal)time)-((decimal)hour)*100;
Not sure if it's a better solution, but if you're on .NET 4.0 or later, you can also go through a string. It seems like "23.40" is a sequence of characters with one interpretation as a double, and another one as a TimeSpan.
If you like that idea, use:
TimeSpan DoubleToTimeSpan(double time)
{
string str = time.ToString("F2", CultureInfo.InvariantCulture);
TimeSpan ts = TimeSpan.ParseExact(str, "h'.'mm", CultureInfo.InvariantCulture);
return ts;
}
Maybe not as fast as the multiply-by-100-and-round approach, though I haven't tested that.
I decided to re-create my question:
decimal dTotal = 0m;
foreach (DictionaryEntry item in _totals)
{
if (!string.IsNullOrEmpty(item.Value.ToString()))
{
dTotal += Convert.ToDecimal(item.Value);
}
}
Console.WriteLine(dTotal / 3600m);
Console.WriteLine(decimal.Round(dTotal / 3600m, 2));
Console.WriteLine(decimal.Divide(dTotal, 3600m));
The above code returns:
579.99722222222222222222222222
580.00
579.99722222222222222222222222
So, that is where my issues are coming from, I really need it to just display the 579.99; but any round, be it decimal.Round or Math.Round still return 580; even the string formats for {0:F} return 580.00.
How can i properly do this?
New answer (to new question)
Okay, so you've got a value of 579.99722222222222222222222222 - and you're asking that to be rounded to two decimal places. Isn't 580.00 the natural answer? It's closer to the original value than 579.99 is. It sounds like you essentially want flooring behaviour, but with a given number of digits. For that, you can use:
var floored = Math.Floor(original * 100) / 100;
In this case, you can do both in one step:
var hours = Math.Floor(dTotal / 36) / 100;
... which is equivalent to
var hours = Math.Floor((dTotal / 3600) * 100) / 100;
Original answer (to original question)
Sounds like you've probably got payTotal in an inappropriate form to start with:
using System;
class Test
{
static void Main()
{
decimal pay = 2087975.7m;
decimal time = pay / 3600;
Console.WriteLine(time); // Prints 579.99325
}
}
This is the problem:
var payTotal = 2087975.7;
That's assigning payTotal to a double variable. The value you've actually got is 2087975.69999999995343387126922607421875, which isn't what you wanted. Any time you find yourself casting from double to decimal or vice versa, you should be worried: chances are you've used the wrong type somewhere. Currency values should absolutely be stored in decimal rather than double (and there are various other Stack Overflow questions talking about when to use which).
See my two articles on floating point for more info:
Binary floating point in .NET
Decimal floating point in .NET
(Once you've got correct results, formatting them is a different matter of course, but that shouldn't be too bad...)
I need to calculate the time difference faken for division most accurately in nano seconds. Please tell me to do this.
At Present i'm using a lower accuracy method in which the problem is that : when the first calculation is performed it shows 87 milliseconds or 65 milliseconds as answer. But when the function is called again second time or more, it only show 0 milliseconds.
The code is :
long startTick = DateTime.Now.Ticks;
double result = (double)22 / 7;
result = System.Math.Round(result, digit);
long endTick = DateTime.Now.Ticks;
long tick = endTick - startTick;
double milliseconds = tick / TimeSpan.TicksPerMillisecond;
time.Text = result + "\nThe division took " + milliseconds + " milliseconds to complete.";
digit is the parameter of function which is variable. No matter what the value of digit is the milliseconds value remains 0 after first calling of function....
Please suggest more accurate way in which calling the same function with different decimal digits will result in different time interval in c# for windows Phone.
I think the memory flush should be done before and after each calculation. But i dont know how to do this.
I don't like this tick method personally for accuracy. I've tried stopwatch also but its not working. Please suggest another method best suited in my case. I want result like : 0.0345 or 0.0714 seconds.
Thanks
You are performing integer division on this line:
double milliseconds = tick / TimeSpan.TicksPerMillisecond;
Even though you are declaring it as a double, a long divided by a long will truncate the decimal. You are better off doing:
double milliseconds = (double)tick / TimeSpan.TicksPerMillisecond;
Or better yet, just ditch the tick stuff all together:
DateTime start = DateTime.Now;
double result = (double)22 / 7;
result = System.Math.Round(result, digit);
DateTime end = DateTime.Now;
double milliseconds = (end - start).TotalMilliseconds;
time.Text = result + "\nThe division took " + milliseconds + " milliseconds to complete.";
You won't be able to get micro or nano level precision, but you will get millisecond precision with a margin of error.
You still may get zero, however. You are trying to time how long a simple division operation takes. You could do millions of division operations in less than a second. You may want to do it 1,000,000 times, then divide the result by a 1,000,000:
DateTime start = DateTime.Now;
for (var i = 0; i < 1000000; i++)
{
double result = (double)22 / 7;
result = System.Math.Round(result, digit);
}
DateTime end = DateTime.Now;
double milliseconds = (end - start).TotalMilliseconds / 1000000;
This still won't be completely realistic, but should get you an actual number.
Since you have the time in ticks, just increase the resolution by multiplying the denominator:
double microseconds = tick / (TimeSpan.TicksPerMillisecond * 1000.0);
Why are you not using StopWatch Class to do your time calulation.
It is meant to the calculate the time the you want ..
Here is a link for your reference.
http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx
//if you want to get the full milliseconds you could also do something like this.
dateStartTime = Convert.ToDateTime(DateTime.Now.TimeOfDay.ToString());
//then where you end the code do this
dateEndTime = Convert.ToDateTime(DateTime.Now.TimeOfDay.ToString());
ddateDuration = (TimeSpan)(dateEndTime - dateStartTime);
then to display out what you are actually looking for in terms of miliseconds do
Console.WriteLine(ddateDuration.ToString().Substring(0, 8));
// or some other method that you are using to display the results