简体   繁体   English

如何计算C#中某些时间跨度的平均值

[英]How to calculate average of some timespans in C#

I already search this question but unfortunately couldn't find proper answer. 我已经搜索了这个问题,但不幸的是找不到正确的答案。

I want to calculate the average of time spent on doing something in 10 different day and I have 10 datetimepicker for start time and also 10 datetimepicker for end time for each day (in total 20 datetimepicker ). 我想计算在10天不同的时间里做某事所花费的平均时间,我每天有10个datetimepicker作为开始时间,还有10个datetimepicker作为结束时间(总共20个datetimepicker )。

now I want to get the average of time spent for work in these 10 days. 现在,我想获得这10天内花在工作上的平均时间。

this is what I've done for calculating timespan in each day and now I don't know how to calculate average if these timespans 这是我每天计算timespan所做的工作,现在我不知道如何计算这些timespans平均值

of course I want to know is there any shorter way to get the job done? 我当然想知道有没有更短的方法来完成这项工作?

DateTime Dt1 = dateTimePicker1.Value;
DateTime Dt2 = dateTimePicker2.Value;
.
.
.
DateTime Dt20 = dateTimePicker20.Value;

TimeSpan Day1 = DateTime.Parse(Dt11.TimeOfDay.ToString()).Subtract(DateTime.Parse(Dt1.TimeOfDay.ToString()));
TimeSpan Day2 = DateTime.Parse(Dt12.TimeOfDay.ToString()).Subtract(DateTime.Parse(Dt2.TimeOfDay.ToString()));
.
.
.

TimeSpan Day10 = DateTime.Parse(Dt20.TimeOfDay.ToString()).Subtract(DateTime.Parse(Dt10.TimeOfDay.ToString()));

I want to find average of Day1 to Day10 我想找到第一天到第十天的平均值

Given an IEnumerable<TimeSpan> you can average them with this extension method: 给定IEnumerable<TimeSpan>您可以使用此扩展方法将它们取平均值:

public static TimeSpan Average(this IEnumerable<TimeSpan> spans) => TimeSpan.FromSeconds(spans.Select(s => s.TotalSeconds).Average());

So, convert your results to a List : 因此,将结果转换为List

var durs = new List<TimeSpan>();
durs.Add(Dt11.TimeOfDay.Subtract(Dt1.TimeOfDay));
durs.Add(Dt12.TimeOfDay.Subtract(Dt2.TimeOfDay));
.
.
.

durs.Add(Dt20.TimeOfDay.Subtract(Dt10.TimeOfDay));

Now compute the average: 现在计算平均值:

var avgDurs = durs.Average();

PS: Created an Aggregate version of @MattJohnson's answer: PS:创建了@MattJohnson答案的Aggregate版本:

public static TimeSpan Mean(this IEnumerable<TimeSpan> source) => TimeSpan.FromTicks(source.Aggregate((m: 0L, r: 0L, n: source.Count()), (tm, s) => {
        var r = tm.r + s.Ticks % tm.n;
        return (tm.m + s.Ticks / tm.n + r / tm.n, r % tm.n, tm.n);
    }).m);

You can find average by instantiating a new TimeSpan based on number of ticks. 您可以通过基于刻度数实例化一个新的TimeSpan来找到平均值。

    var time_spans = new List<TimeSpan>() { new TimeSpan(24, 10, 0), new TimeSpan(12, 0, 45), new TimeSpan(23, 30, 0), new TimeSpan(11, 34, 0) };

    var average = new TimeSpan(Convert.ToInt64(time_spans.Average(t => t.Ticks)));

     Console.WriteLine(average); 

result 17:48:41.2500000 结果17:48:41.2500000

Just to follow up on NetMage's perfectly good answer, note that his Average extension method is using .TotalSeconds , which returns a double of whole and fractional seconds, with millisecond precision. 为了跟进NetMage的完美回答,请注意,他的Average扩展方法使用.TotalSeconds ,该方法以毫秒为单位返回整数秒和分数秒的double That is probably fine if you are taking values from time-pickers, but in the general case it will result in a small loss of precision. 如果您从时间选择器中获取值,那可能很好,但是在一般情况下,这将导致精度的少量损失。

Additionally, the TimeSpan.FromSeconds method can overflow when dealing with large values. 此外,在处理大值时, TimeSpan.FromSeconds方法可能会溢出。 This can be reproduced even when not averaging: 即使不求平均也可以重现:

TimeSpan.FromSeconds(TimeSpan.MaxValue.TotalSeconds)  // will throw an OverflowException

Patrick Hofman made a good point in the comments that just switching from seconds to ticks could also result in overflow, and thus another solution is needed. 帕特里克·霍夫曼(Patrick Hofman)在评论中指出了一个好观点,即仅从秒切换到滴答声也可能导致溢出,因此需要另一种解决方案。

Adapting the technique given in this answer , we can compute the average of a collection of TimeSpan values using an arithmetic mean approach, without loss of precision and without overflowing: 调整此答案中给出的技术,我们可以使用算术平均值方法来计算TimeSpan值集合的平均值 ,而不会损失精度,也不会发生溢出:

public static TimeSpan Mean(this ICollection<TimeSpan> source)
{
    if (source == null)
        throw new ArgumentNullException(nameof(source));

    long mean = 0L;
    long remainder = 0L;
    int n = source.Count;
    foreach (var item in source)
    {
        long ticks = item.Ticks;
        mean += ticks / n;
        remainder += ticks % n;
        mean += remainder / n;
        remainder %= n;
    }

    return TimeSpan.FromTicks(mean);
}

Use it similarly to other extension methods, such as: 与其他扩展方法类似地使用它,例如:

TimeSpan average = mylistoftimespans.Mean();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM