我有一个对象列表,它们具有StartAt
和EndAt
,DateTime
类型的属性,表示阅读会话的开始和结束时间。我想计算一下每天阅读的总时间,考虑到一次阅读可以跨越两天。例如,如果阅读课程从5月1日晚上11:00开始,到5月2日凌晨1:30结束,我想在5月1日计算1小时的阅读,在5月2日计算1.5小时的阅读。如何在C#中使用LINQ实现这一点?
DateTime currentDate = DateTime.UtcNow;
DateTime previousDate = currentDate.AddDays(-1);
var result = readingSessions
.Where(x => x.StartAt.Date == currentDate.Date || x.StartAt.Date == previousDate.Date)
.GroupBy(x => x.StartAt.Date)
.Select(x => new
{
Date = x.Key,
Sum = TimeSpan.FromSeconds(x.Sum(y => (y.EndAt - y.StartAt).TotalSeconds))
})
.ToList();
public class ReadingSession
{
public DateTime StartAt {get;set;}
public DateTime EndAt {get;set;}
}
详情
开始时间 | 结束时间 |
---|---|
2023-05-01 08:00:00 PM | 2023-05-01 09:00:00 PM |
2023-05-01 11:00:00 PM | 2023-05-02 01:30:00 AM |
如何计算?
假设我们想根据给定的StartAt和EndAt时间计算5月1日和5月2日的总阅读持续时间。
对于第一行,用户在5月1日下午8:00开始阅读,并在同一天晚上9:00结束。因此,5月1日的总阅读时长为1小时。
对于第二行,用户在5月1日的11:00 PM开始阅读,并在5月2日的1:30 AM结束。在这种情况下,我们需要将阅读时间分为两部分:一个是5月1日的,一个是5月2日的。
5月1日,用户从晚上11:00到晚上11:59阅读,总共1小时。5月2日,用户从12:00 AM阅读到1:30 AM,总共1. 5小时。因此,5月1日的总阅读时长为1小时,5月2日的总阅读时长为1.5小时。
结果应该是什么样的?
5月1日,阅读器从晚上8点开始,到晚上9点结束,这给了我们1小时的持续时间。他们也从晚上11点开始阅读,一直持续到凌晨12点,这又增加了一个小时,5月1日总共有2个小时。
5月2日,读者从凌晨12:00开始阅读,到凌晨1:30结束,这给了我们1. 5小时的持续时间。
因此,5月1日的总阅读时间为2小时,5月2日为1.5小时。
4条答案
按热度按时间liwlm1x91#
下面是我解决的方法:首先,我确定ReadingSession是否跨越多天。如果它跨越了几天,我会把它分开。剩下的就和你已经做的差不多了。
xienkqul2#
以下是我的解决方案:
有几点需要考虑:
1.最好是将和提取到不同的函数中
1.如果阅读会话的持续时间超过2天,则代码将仅对开始日期和结束日期的持续时间求和
mv1qrgav3#
谢谢你澄清你的问题。我认为你想要的是一种方法,将一个单一的
ReadingSession
和分裂成 * 每日 * 阅读会话。这将为您提供仅在一天内发生的会话列表。例如,如果一个阅读会话持续了5天,下面将返回5个单独的阅读会话的列表,每天一个,第一个在开始时间开始,最后一个在结束时间结束,其他的都在一天的开始/结束:
现在,我们可以把我们最初的阅读课程列表,分成每天的课程,就像这样:
现在,您的原始代码应该可以正常工作了,因为
dailyReadingSessions
中的每个阅读会话只跨越一个Date
。dwbf0jvd4#
假设阅读会话总是少于24小时(例如跨度最多两天),那么您可以拆分跨越午夜的任何阅读会话,然后使用代码对结果进行分组和计算。我省略了
Where
方法,因为我不确定你希望最终的过滤器是什么:注意:这不是非常有效,因为它为每一天的阅读会话生成一个数组,然后将其丢弃-您可以通过扫描列表两次并使用union将一天的会话与两天的会话合并,以牺牲时间为代价提高空间效率,但这可能不值得复杂性。这让我觉得
SplitUnion
方法可能很好。