场景描述:
武汉热浪网吧收费标准如下:
6:00-12:00收费5.5/h,实时收费
12:00-18:00收费6/h,实时收费
18:00-23:00收费7/h,实时收费
23:00-第二天6:00,收费5/h,上限15收费
上限收费指实时收费超出上限时,按照上限收费,否则实时收费。
一.声明时段对象:
1 /// <summary>
2 /// 时段收费区间
3 /// </summary>
4 public class State
5 {
6 public TimeSpan start { get; set; }
7 public TimeSpan end { get; set; }
8 public double pay { get; set; }
9 public double maxpay { get; set; }
10
11 /// <summary>
12 /// 某时间内的费用/小时
13 /// </summary>
14 /// <param name="_start">开始时间</param>
15 /// <param name="_end">结束时间</param>
16 /// <param name="_pay">每小时费用</param>
17 /// <param name="_maxpay">时段上限收费,为0时代表实时收费</param>
18 public State(TimeSpan _start, TimeSpan _end,double _pay,double _maxpay)
19 {
20 this.start = _start;
21 this.end= _end;
22 this.pay = _pay;
23 this.maxpay = _maxpay;
24 }
25 }
二.计算类
1 public class Compute
2 {
3 List<State> states = null;
4 public Compute(List<State> _states)
5 {
6 this.states = _states;
7 }
8
9 public double GetResult(DateTime start,DateTime end)
10 {
11 double result = 0;
12 if (this.states != null)
13 {
14 TimeSpan totlaSpan = end - start;
15 if (totlaSpan.TotalDays >= 1)
16 {
17 int days = Convert.ToInt32(totlaSpan.TotalDays);
18 result += FullDayPay() * days;
19 //证明有余的天数
20 if ((totlaSpan.TotalDays - days) > 0)
21 {
22 this.TimespanPay(start.AddDays(days), end, ref result);
23 }
24 }
25 else
26 {
27 this.TimespanPay(start, end, ref result);
28 }
29 }
30 return result;
31 }
32
33 /// <summary>
34 /// 按时段收费
35 /// </summary>
36 /// <param name="start"></param>
37 /// <param name="end"></param>
38 /// <returns></returns>
39 private void TimespanPay(DateTime start,DateTime end,ref double result)
40 {
41 // 时间所处的时段收费区间
42 State spanState = this.GetSpan(start);
43 // 此收费区间段结束时间
44 DateTime spanEnd = new DateTime(start.Year, start.Month, start.Day).Add(spanState.end);
45 TimeSpan span;
46 bool next = false;
47 // 如果结束时间在收费区间段之内
48 if (end < spanEnd)
49 {
50 //计算结费总的时长
51 span = end - start;
52 }
53 else
54 {
55 span = spanEnd - start;
56 next = true;
57 }
58 // 计算区间内费用
59 double payment = span.TotalHours * spanState.pay;
60 if (spanState.maxpay > 0)
61 {
62 result += Math.Min(payment, spanState.maxpay);
63 }
64 else
65 {
66 result += payment;
67 }
68 if (next)
69 {
70 this.TimespanPay(spanEnd, end, ref result);
71 }
72 }
73
74 /// <summary>
75 /// 根据开始时间获取所属的时段
76 /// </summary>
77 /// <param name="start"></param>
78 /// <returns></returns>
79 private State GetSpan(DateTime start)
80 {
81 IEnumerable<State> states = this.states.Where(a => start >= new DateTime(start.Year, start.Month, start.Day).Add(a.start));
82 return states.Last();
83 }
84
85 /// <summary>
86 /// 获取全天的收费
87 /// </summary>
88 /// <returns></returns>
89 private double FullDayPay()
90 {
91 double result = 0;
92 foreach (State item in this.states)
93 {
94 if (item.maxpay > 0)
95 {
96 result += item.maxpay;
97 }
98 else
99 {
100 result += (item.end - item.start).TotalHours * item.pay;
101 }
102 }
103 return result;
104 }
105 }
三.调用
1 List<State> states = new List<State>
2 {
3 new State(new TimeSpan(6,0,0),new TimeSpan(12,0,0),5.5,0),
4 new State(new TimeSpan(12,0,0),new TimeSpan(18,0,0),6,0),
5 new State(new TimeSpan(18,0,0),new TimeSpan(23,0,0),7,0),
6 new State(new TimeSpan(23,0,0),new TimeSpan(1,6,0,0),5,15),
7 };
8
9 //假如上网时间从2019-9-20 17:23-2019-9-22 22:10
10 DateTime start = new DateTime(2019,9,20,17,23,0);
11 DateTime end = new DateTime(2019, 9, 22, 22, 10, 0);
12
13 Compute c = new Compute(states);
14 Console.WriteLine(c.GetResult(start, end));