场景描述:

武汉热浪网吧收费标准如下:

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)); 
02-01 15:12