C# 如何计算多个重叠日期时间的总秒数
我试图找到一种方法来计算特定设备由于不同类型的错误而发生故障的总秒数,这些错误有开始时间和结束时间,并且可能发生在同一时刻但持续时间不同 这是我收集的日期时间:C# 如何计算多个重叠日期时间的总秒数,c#,datetime,C#,Datetime,我试图找到一种方法来计算特定设备由于不同类型的错误而发生故障的总秒数,这些错误有开始时间和结束时间,并且可能发生在同一时刻但持续时间不同 这是我收集的日期时间: private class TimeLapse { public DateTime StartTime { get; set; } public DateTime EndTime { get; set; } } Dictionary<string, List<TimeLapse>> _devic
private class TimeLapse
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}
Dictionary<string, List<TimeLapse>> _devices = new Dictionary<string, List<TimeLapse>>();
私有类时间点
{
公共日期时间开始时间{get;set;}
公共日期时间结束时间{get;set;}
}
字典_devices=新字典();
其中,字典中的字符串是设备的名称
但我不知道从哪里开始不去构建一个恶心的代码。
任何人都有同样的问题需要解决吗?一种方法是使用附加方法扩展类,该方法将合并
TimeLapse
对象列表,方法是将重叠的任何对象合并为单个TimeLapse
,然后返回此集合。如果我们这样做,那么我们可以把集合中每个项目的持续时间相加。您还可以添加一个属性,该属性公开TimeLapse
对象的持续时间
:
private class TimeLapse
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan Duration => (EndTime - StartTime).Duration();
public static List<TimeLapse> Merge(List<TimeLapse> items)
{
if (items == null || items.Count < 2) return items;
var results = new List<TimeLapse>();
foreach (var item in items)
{
var overlappingItem = results.FirstOrDefault(item.OverlapsWith);
if (overlappingItem == null) results.Add(item);
else overlappingItem.CombineWith(item);
}
return results;
}
private bool OverlapsWith(TimeLapse other)
{
return other != null &&
other.StartTime <= EndTime &&
other.EndTime >= StartTime;
}
private void CombineWith(TimeLapse other)
{
if (!OverlapsWith(other)) return;
if (other.StartTime < StartTime) StartTime = other.StartTime;
if (other.EndTime > EndTime) EndTime = other.EndTime;
}
}
输出
< p>我不确定你会觉得什么“恶心”,但是如果你只需要每个时间段的秒数,你就可以创建一个方法来恢复你的TimeLaSe类。
private class TimeLapse
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public double GetSecondsPassed() {
return (EndTime - StartTime).TotalSeconds
}
}
两个DateTime对象之间的差异返回一个对象。而不是有一个你的TimeLapse对象字典,你可以有一个双字典
var\u devices=new Dictionary()
通过编写扩展方法演示LINQ之美
/// <summary>
/// Gets the duration of the set union of the specified intervals.
/// </summary>
/// <param name="timeLapses">Sequence of <see cref="TimeLapse"/> ordered by <see cref="TimeLapse.StartTime"/>.</param>
public static TimeSpan UnionDurations(this IEnumerable<TimeLapse> timeLapses)
{
using (var e = timeLapses.GetEnumerator())
{
if (!e.MoveNext()) // no items, no duration
return TimeSpan.Zero;
var prev = e.Current;
var total = prev.EndTime - prev.StartTime; // set running total to duration of 1st interval
while (e.MoveNext())
{
var curr = e.Current;
if (curr.StartTime < prev.StartTime) throw new Exception($"{nameof(timeLapses)} are not in ascending {nameof(TimeLapse.StartTime)} order.");
var increase = curr.EndTime - (curr.StartTime > prev.EndTime ? curr.StartTime : prev.EndTime);
if (increase <= TimeSpan.Zero) continue;
total += increase;
prev = curr;
}
return total;
}
}
//
///获取指定间隔的集合并集的持续时间。
///
///按顺序排列的顺序。
公共静态时间跨度联合持续时间(此IEnumerable timeLapses)
{
使用(var e=timeLapses.GetEnumerator())
{
if(!e.MoveNext())//没有项目,没有持续时间
返回TimeSpan.0;
var prev=当前值;
var total=prev.EndTime-prev.StartTime;//将运行总计设置为第一个间隔的持续时间
while(如MoveNext())
{
var curr=e.电流;
如果(curr.StartTime上一个结束时间?当前开始时间:上一个结束时间);
如果(增加新的
{
装置=千伏钥匙,
故障持续时间=千伏值
//.OrderBy(tl=>tl.StartTime)//如果StartTime已经订购,则可以删除此行
.UnionDurations()
})
.ToList();
//{Device=A,FaultyDuration=06:00:00}
//{Device=B,FaultyDuration=00:00:00}
建议:1)按开始时间将每个开始/结束时间放入一个有序列表中。2)“持续时间”是最晚的结束时间-最早的开始时间。3)迭代列表:减去每个“洞”在结束时间和开始时间之间没有重叠的地方。4)瞧,这应该是你的结果。你到目前为止试过什么?请记住,没有在线代码生成器服务。@Daniel Fuchs-OP要求的是“算法”问:有什么建议吗?@paulsm4要求某人提供算法基本上就是要求某人为您编写代码。我们不是代码编写服务。Nedo可以尝试提出自己的算法。如果他们在实现过程中遇到特定问题,他们可以创建一个。所以你基本上是在问如何组合所有重叠的TimeLapse
对象,然后对它们的持续时间进行求和吗?这里有一个问题(确实是在计算持续时间的任何地方)是带夏令时的时区。如果可能在过渡期间发生夏令时转换,则不能减去当地时间。这正是我试图实现的目标。
var _devices = new Dictionary<string, double>()
/// <summary>
/// Gets the duration of the set union of the specified intervals.
/// </summary>
/// <param name="timeLapses">Sequence of <see cref="TimeLapse"/> ordered by <see cref="TimeLapse.StartTime"/>.</param>
public static TimeSpan UnionDurations(this IEnumerable<TimeLapse> timeLapses)
{
using (var e = timeLapses.GetEnumerator())
{
if (!e.MoveNext()) // no items, no duration
return TimeSpan.Zero;
var prev = e.Current;
var total = prev.EndTime - prev.StartTime; // set running total to duration of 1st interval
while (e.MoveNext())
{
var curr = e.Current;
if (curr.StartTime < prev.StartTime) throw new Exception($"{nameof(timeLapses)} are not in ascending {nameof(TimeLapse.StartTime)} order.");
var increase = curr.EndTime - (curr.StartTime > prev.EndTime ? curr.StartTime : prev.EndTime);
if (increase <= TimeSpan.Zero) continue;
total += increase;
prev = curr;
}
return total;
}
}
var input = new Dictionary<string, IList<TimeLapse>>
{
{
"A",
new[]
{
new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 0, 0, 0), EndTime = new DateTime(2019, 1, 17, 3, 0, 0)},
new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 1, 0, 0), EndTime = new DateTime(2019, 1, 17, 2, 0, 0)},
new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 1, 0, 0), EndTime = new DateTime(2019, 1, 17, 4, 0, 0)},
new TimeLapse{ StartTime = new DateTime(2019, 1, 17, 5, 0, 0), EndTime = new DateTime(2019, 1, 17, 7, 0, 0)}
}
},
{
"B",
new TimeLapse [0]
}
};
var result = input
.Select(kv => new
{
Device = kv.Key,
FaultyDuration = kv.Value
// .OrderBy(tl => tl.StartTime) // this line can be removed if already ordered by StartTime
.UnionDurations()
})
.ToList();
// { Device = A, FaultyDuration = 06:00:00 }
// { Device = B, FaultyDuration = 00:00:00 }