C# 在这个算法中,在两个可能跨越不同天的时间跨度之间找到一个TimeOfDay,我遗漏了什么?
我有一个24小时内可用时间的C# 在这个算法中,在两个可能跨越不同天的时间跨度之间找到一个TimeOfDay,我遗漏了什么?,c#,.net,.net-4.0,timespan,C#,.net,.net 4.0,Timespan,我有一个24小时内可用时间的列表,以及两个时间跨度,minTime和maxTime 我需要在列表中找到一天中位于minTime和maxTime之间的时间,但是由于这在多个时区中使用,minTime和maxTime可以在不同的日子中,时间跨度大约为下午1点到次日凌晨1点 我最近接触到的是这个,但我觉得这里缺少了一些主要组件,或者做了一些非常低效的事情,因为我对TimeSpan对象相当陌生。我只是不知道是什么 // Make new TimeSpan out of maxTime to elimin
列表
,以及两个时间跨度
,minTime和maxTime
我需要在列表中找到一天中位于minTime
和maxTime
之间的时间,但是由于这在多个时区中使用,minTime和maxTime可以在不同的日子中,时间跨度大约为下午1点到次日凌晨1点
我最近接触到的是这个,但我觉得这里缺少了一些主要组件,或者做了一些非常低效的事情,因为我对TimeSpan
对象相当陌生。我只是不知道是什么
// Make new TimeSpan out of maxTime to eliminate any extra days (TotalHours >= 24),
// then check if time on the MaxTime is earlier than the MinTime
if (new TimeSpan(maxTime.Hours, maxTime.Minutes, maxTime.Seconds) < minTime)
{
// If time on MaxTime is earlier than MinTime, the two times span separate days,
// so find first time after minTime OR before maxTime
nextAvailableTime = Times.FirstOrDefault(p =>
(p.Time.TimeOfDay >= minTime || (p.Time.TimeOfDay < maxTime))
&& p.Count < ConcurrentAppointments);
}
else
{
// If time on MaxTime is later than MinTime, the two times are for the same day
// so find first time after minTime AND before maxTime
nextAvailableTime = Times.FirstOrDefault(p =>
(p.Time.TimeOfDay >= minTime && p.Time.TimeOfDay < maxTime)
&& p.Count < ConcurrentAppointments);
}
我相当肯定我在这里遗漏了一些重要的东西,或者应该有一种更有效的方法来做这件事,我不知道,但我真的想不出它可能是什么。我的算法有问题吗?或者更有效地在两个可能跨越不同天的时间跨度
之间查找时间间隔
更新
我根据我的经验找出了我遗漏的东西。我忘了日期其实很重要,因为我的时间跨越不同的时区
以我上面的夏威夷时区为例,安排周一的约会会导致错误地安排周日晚上的夏威夷约会
我的解决方案是,在为24小时制的“第一个窗口”安排约会之前,检查前一天是否有效,并在与maxTime
比较时,通过.AddDays(maxTime.Days)
调整约会日期
// If time on MaxTime is earlier than MinTime, the two times span separate days,
// so find first time after minTime OR before maxTime if previous day has appointments set as well
var isPreviousDayValid = IsValidDate(AppointmentDate.AddDays(-1));
nextAvailableTime = Times.FirstOrDefault(p =>
(p.Time.TimeOfDay >= minTime
|| (p.Time.AddDays(maxTime.Days).TimeOfDay < maxTime && isPreviousDayValid)
) && p.Count < ConcurrentAppointments);
//如果MaxTime上的时间早于MinTime,则这两个时间跨越不同的天,
//所以,如果前一天也有预约,那么在minTime之后或maxTime之前找到第一次
var isPreviousDayValid=IsValidDate(任命日期.AddDays(-1));
nextAvailableTime=Times.FirstOrDefault(p=>
(p.Time.TimeOfDay>=minTime
||(p.Time.AddDays(maxTime.Days).TimeOfDay
总体思路是,不要比较时间,要比较日期;把你的窗口从时间转换成日期,剩下的就很容易了
您可以为列表中的每个项目生成一组新实例,以比较最小值和最大值,使用作为计算要比较的范围上限的基础
这假设您的minTime
始终小于maxTime
,并且如果您通过在上有一个值来表示重叠到新一天的范围
你必须看看是否有前一天和后一天的窗口。例如:
(1) (2) (3) (4) (5)
----x----x----x----x----x----
(1) - 1/1/1900 11:00 PM - Date component in your list - 1 day + min time
(2) - 1/2/1900 12:05 AM - this is the date and time from your list
(3) - 1/2/1900 01:00 AM - Date component in your list - 1 day + max time
(4) - 1/2/1900 11:00 PM - Date component in your list + min time
(5) - 1/3/1900 01:00 AM - Date component in your list + max time
这意味着您需要创建两个窗口,并检查是否存在以下任一窗口:
nextAvailableTime = Times.FirstOrDefault(p => {
// Check count first, get this out of the way.
if (!(p.Count < ConcurrentAppointments)) return false;
// The date time and the date component
DateTime dt = p.Time;
DateTime d = dt.Date;
// The windows
DateTime prevWindowMin = d.AddDays(-1) + minTime;
DateTime prevWindowMax = d.AddDays(-1) + maxTime;
DateTime windowMin = d + minTime;
DateTime windowMax = d + maxTime;
// Is it in *either* window;
return
(prevWindowMin <= dt && dt <= prevWindowMax)||
(windowMin <= dt && dt <= windowMax);
});
nextAvailableTime=Times.FirstOrDefault(p=>{
//先检查一下计数,把这个让开。
如果(!(p.Count (prevWindowMin@Rachel,你能提供一个反例,说明这是无法使用的吗
nextAvailableTime = Times.OrderBy(i => i.Time).FirstOrDefault(i => i.Count < ConcurrentAppointments &&
i.Time.TimeOfDay >= minTime &&
i.Time.TimeOfDay < maxTime
);
@pst“最有效”?:)我有一个我认为有效的解决方案…我只是觉得它没有优化,还有一个更好的方法我错过了,因为我对TimeSpan
objectBetter:)相当不熟悉我将把标题放在技术上。如果minDate
大于maxDate
,我们可以假设它表示两天的时间窗口吗?@casperOneminDate
永远不会大于maxDate
,但是minDate.Hours
可以大于maxDate.Hours
,在这种情况下是的uld表示超过一天的时间窗口是minDate
和maxDate
DateTime
结构和实际日期组件,或者其中的日期不相关?如果minTime
大于maxTime
,则表示窗口在第二天?这在cas中不起作用e其中minTime和maxTime结束于两个不同的日期,例如minTime=new TimeSpan(13,0,0)
和maxTime=new TimeSpan(25,0,0)
(东部标准时间上午8点到晚上8点->UTC下午1点到凌晨1点)@Rachel,谢谢你的反馈。你觉得我的更新怎么样?谢谢你更新的答案,但是我意识到我没有检查算法中的日期,没有遗漏我的实际语法。很抱歉这个令人困惑的问题,我把它归咎于这是一个漫长的一周结束时的一个星期五,我的大脑感到兴奋:)我知道我做错了什么,但我不知道这与我使用的语法(而不是算法本身)有什么关系。谢谢,我明天必须运行一些测试来确保这一点,看看它与我当前的方法相比如何,但你的逻辑似乎是正确的。(这是为了从所有不同的时区一次安排数千个约会,所以性能对我来说很重要)@Rachel看到最后一段(你可能错过了);如果是其他日期,你可以得到date
组件并使用它(我想象你真正拥有的)。这意味着您不必每次都计算最小和最大DateTime
窗口。不管怎样,在任何一台像样的机器上,这些操作都应该是微不足道的,即使是数千件物品。@rachel我必须意识到这是1/2。如果要解决这个问题,您还必须使用前一天(因为您的时间可能与前一天重叠).也就是说,只需使用当前日期和之前的日期作为基础,然后检查betwe
nextAvailableTime = Times.OrderBy(i => i.Time).FirstOrDefault(i => i.Count < ConcurrentAppointments &&
i.Time.TimeOfDay >= minTime &&
i.Time.TimeOfDay < maxTime
);
var Times = new List<AppointmentTime>();
var ConcurrentAppointments = 10;
Times.AddRange(new[]{
new AppointmentTime()
{
Count = 0,
Time = new DateTime(2012, 12, 1, 1, 30, 0)
},
new AppointmentTime()
{
Count = 0,
Time = new DateTime(2012, 12, 1, 13, 5, 0)
},
new AppointmentTime()
{
Count = 0,
Time = new DateTime(2012, 12, 1, 11, 0, 0)
}});
var minTime = new TimeSpan(13, 0, 0);
var maxTime = new TimeSpan(25, 0, 0);
// Version 1
// Not so performant, ~0.48 seconds for a loop of 1,000,000 iterations, see Version 2
//nextAvailableTime = Times.OrderBy(i => i.Time).FirstOrDefault(i => i.Count < ConcurrentAppointments &&
// i.Time.TimeOfDay.TotalSeconds >= Math.Min(maxTime.TotalSeconds % (3600 * 24), minTime.TotalSeconds)
// );
// Version 2
// Better performance, ~0.12 seconds for 1,000,000 iterations. We calculate the
// constant value we are comparing with outside the lambda expression
// We calculate the `totalSeconds` variable as the minimum of seconds within the
// 24h day. For that, we use the `% (3600 * 24)` operation to exclude the days.
var totalSeconds = (int)Math.Min(maxTime.TotalSeconds % (3600 * 24), minTime.TotalSeconds);
// We create a timespan variable called `timeOfDay` which is based on the
// `totalSeconds` variable above. Note that the day is not essential.
var timeOfDay = (new DateTime(1, 1, 1, totalSeconds / 3600, (totalSeconds % 3600) / 60, totalSeconds % 60)).TimeOfDay;
// Returns the `AppointmentTime` with the 01:30 AM. Note, again, that the
// date of the `AppointmentTime` is not essential
nextAvailableTime = Times.FirstOrDefault(i => i.Count < ConcurrentAppointments &&
i.Time.TimeOfDay >= timeOfDay
);