Reputation: 296
I'm currently working on an app that calculates the price a user has to pay for a service based on how much time he's spent using said service. The fee is $3.30 for the first hour and then $1.15 for every half hour after that. My timer looks something like this:
private void timer()
{
DispatcherTimer timer = new DispatcherTimer();
timer.Tick +=
delegate(object s, EventArgs args)
{
TimeSpan time = (DateTime.Now - StartTime);
this.Time.Text = string.Format("{0:D2}:{1:D2}:{2:D2}", time.Hours, time.Minutes, time.Seconds);
};
timer.Interval = new TimeSpan(0, 0, 1); // one second
timer.Start();
}
The point being that the timer AND the price to pay should be shown on screen and update automatically with the passing of time (the timer already does that.)
As for the price itself, I thought of using a combination of if/else and foreach, but so far, I've accomplished nothing...
Upvotes: 0
Views: 1627
Reputation: 108790
A few notes:
decimal
and not double
to represent moneyMath.Ceiling
is great. No need to jump through hoops to get Math.Round
to do what you want.Encapsulate your pricing logic into a simple side-effect free method that doesn't interact with external services, such as the clock.
This makes it easy to test the method in isolation.
I'd write it like this:
public decimal CostByTime(TimeSpan t)
{
if(t < TimeSpan.Zero)
throw new ArgumentOutOfRangeExeception("t", "Requires t>=0");
if(t == TimeSpan.Zero)
return 0;
double hours = t.TotalHours;
if(hours <= 1)
return 3.30m;
else
return 3.30m + (int)Math.Ceiling((hours-1)*2) * 1.15m
}
And then in your view you can use:
TimeSpan billableTime = DateTime.UtcNow - StartTime;
decimal cost = CostByTime(billableTime);
Time.Text = billableTime.ToString(...);
Cost.Text = cost.ToString();
Upvotes: 1
Reputation: 2699
If the scheme is such that the cost is added as soon as a segment starts then you can calculate the number of half hours that have started, after the initial hour, as:
Math.Round((hours - 1) / 0.5 + 0.5)
And the cost is then calculated as:
double hours = (DateTime.UtcNow - StartTime).TotalHours;
double cost;
if (hours < 1)
cost = 3.30;
else
cost = 3.30 + Math.Round((hours - 1) / 0.5 + 0.5) * 1.15;
Upvotes: 1
Reputation: 67193
Something like this. (You left out how partial hours are handled so I ignored them.)
double span = (DateTime.Now - StartTime).TotalHours;
decimal cost = 0.0;
if (span > 0)
cost = 3.30 + ((span - 1) * 1.15);
Upvotes: 2