场景描述:
武汉热浪网吧收费标准如下:
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));