using System.Collections.Generic;
using System.Threading.Tasks;
var rules = new List<breakpromisepunishrule>
{ new breakpromisepunishrule { breakPromiseTimes = 2, punishDays = 4 },
new breakpromisepunishrule { breakPromiseTimes = 3, punishDays = 7 },
new breakpromisepunishrule { breakPromiseTimes = 4, punishDays = 5 },
foreach (var item in rules)
Console.WriteLine($"规则:次数{item.breakPromiseTimes} 惩罚天数{item.punishDays}");
var absenceRecords = new List<DateTime>
new DateTime(2024, 1, 1),
new DateTime(2024, 1, 3),
new DateTime(2024, 1, 28),
new DateTime(2024, 2, 1),
new DateTime(2024, 2, 3),
var penaltyIntervals = CalculatePenalty(absenceRecords, rules);
foreach (var item in absenceRecords)
Console.WriteLine($"爽约时间:{item}");
foreach (var interval in penaltyIntervals)
Console.WriteLine($"惩罚区间:{interval.startOfSlot.ToString("yyyy-MM-dd")} ~ {interval.endOfSlot.ToString("yyyy-MM-dd")}");
var penaltyIntervals2 = MergeTimeSlot(penaltyIntervals);
foreach (var item2 in penaltyIntervals2)
Console.WriteLine($"归并后惩罚区间:{item2.startOfSlot.ToString("yyyy-MM-dd")} ~ {item2.endOfSlot.ToString("yyyy-MM-dd")}");
public static List<TimeSlot> CalculatePenalty(List<DateTime> absenceRecords,List<breakpromisepunishrule> rules)
var penaltyIntervals = new List<TimeSlot>();
if (absenceRecords==null||rules==null||!absenceRecords.Any()||!rules.Any())
return new List<TimeSlot>();
rules = rules.OrderBy(c => c.breakPromiseTimes).ToList();
absenceRecords= absenceRecords.OrderBy(c=>c).Select(c=>c.Date).ToList();
var startDate = DateTime.MinValue;
var endDate = DateTime.MinValue;
var monthGroups = absenceRecords.GroupBy(c => c.Date.Month).ToList();
foreach (var group in monthGroups)
foreach (var record in group)
var rule = new breakpromisepunishrule();
if (count >= rules.Max(c=>c.breakPromiseTimes))
rule = rules.LastOrDefault();
rule = rules.FirstOrDefault(c => c.breakPromiseTimes == count);
endDate = record.AddDays((int)rule.punishDays - 1);
penaltyIntervals.Add(new TimeSlot { startOfSlot = record, endOfSlot = endDate });
public static List<TimeSlot> MergeTimeSlot(List<TimeSlot> timeSlots)
if (timeSlots == null || timeSlots.Count == 0)
return new List<TimeSlot>();
var orderTimeSlots = timeSlots.OrderBy(c => c.startOfSlot).ToList();
List<TimeSlot> mergedTimeSlots = new List<TimeSlot>();
var currentSlot = orderTimeSlots[0];
foreach (var slot in orderTimeSlots)
if (slot.startOfSlot <= currentSlot.endOfSlot)
if (slot.startOfSlot>=currentSlot.startOfSlot&&slot.startOfSlot<=currentSlot.endOfSlot)
currentSlot.endOfSlot = currentSlot.endOfSlot.AddDays((slot.endOfSlot - slot.startOfSlot).TotalDays+1);
if (slot.endOfSlot > currentSlot.endOfSlot)
currentSlot.endOfSlot = slot.endOfSlot;
currentSlot.endOfSlot = currentSlot.endOfSlot;
mergedTimeSlots.Add(currentSlot);
mergedTimeSlots.Add(currentSlot);
public DateTime startOfSlot { get; set; }
public DateTime endOfSlot { get; set; }
public partial class breakpromisepunishrule
public long breakPromiseTimes { get; set; }
public long punishDays { get; set; }