C# 计算;“工作时间”;使用TimePeriod.NET';Calendars PeriodCollector提供了意外的结果
我试图计算服务级别协议的到期日,同时,我还需要反向计算服务级别协议 我一直在努力计算“工作时间”(即在一组天内可以工作的时间),并决定使用第三方库来完成该任务。我需要能够做两件事:C# 计算;“工作时间”;使用TimePeriod.NET';Calendars PeriodCollector提供了意外的结果,c#,datetime,C#,Datetime,我试图计算服务级别协议的到期日,同时,我还需要反向计算服务级别协议 我一直在努力计算“工作时间”(即在一组天内可以工作的时间),并决定使用第三方库来完成该任务。我需要能够做两件事: 给定开始日期时间和时间间隔,您应该会收到服务级别协议到期日期(到期日期)的日期时间 给定开始DateTime和结束DateTime,您应该会收到服务级别协议所需时间的TimeSpan 所有源代码(测试项目处于打开状态)。我有一个ServiceLevelManager类来完成所有工作。它需要列出工作日和假期,以确定
- 给定开始日期时间和时间间隔,您应该会收到服务级别协议到期日期(到期日期)的日期时间
- 给定开始
和结束DateTime
,您应该会收到服务级别协议所需时间的DateTime
TimeSpan
ServiceLevelManager
类来完成所有工作。它需要列出工作日
和假期
,以确定哪些时间可以工作。CalendarPeriodCollector
类给出了意外的结果。在从时间跨度确定到期日时,确实起作用的期望值在我反向计算时计算不正确
有人能看到我是否做错了什么,或者图书馆是否有bug吗
namespace ServicePlanner
{
using System;
using System.Collections.Generic;
using Itenso.TimePeriod;
public class ServicePlannerManager
{
public ServicePlannerManager(IEnumerable<WorkDay> workDays, IEnumerable<HolidayPeriod> holidays)
{
this.WorkDays = workDays;
this.Holidays = holidays;
}
public IEnumerable<WorkDay> WorkDays { get; set; }
public IEnumerable<HolidayPeriod> Holidays { get; set; }
public TimeSpan GetRemainingWorkingTime(DateTime start, DateTime dueDate)
{
var filter = new CalendarPeriodCollectorFilter();
foreach (var dayOfWeek in this.WorkDays)
{
filter.CollectingDayHours.Add(new DayHourRange(dayOfWeek.DayOfWeek, new Time(dayOfWeek.StartTime), new Time(dayOfWeek.EndTime)));
}
foreach (var holiday in this.Holidays)
{
filter.ExcludePeriods.Add(new TimeBlock(holiday.StartTime, holiday.EndTime));
}
var range = new CalendarTimeRange(start, dueDate);
var collector = new CalendarPeriodCollector(filter, range);
collector.CollectHours();
var duration = collector.Periods.GetTotalDuration(new TimeZoneDurationProvider(TimeZoneInfo.FindSystemTimeZoneById("UTC")));
return duration;
//var rounded = Math.Round(duration.TotalMinutes, MidpointRounding.AwayFromZero);
//return TimeSpan.FromMinutes(rounded);
}
}
}
我想知道我是否错误地使用了收集器,或者收集器是否有bug。这看起来是一个解决常见问题的很好的库 最好的方法是输出句点集合中的句点,以帮助您调试问题。 我已经重写了您的测试,以使用示例文档中的基类型:
[Test, TestCaseSource("LocalSource")]
public void SO_GetRemainingWorkingTimeWithHolidayShouldOnlyEnumerateWorkingTime(DateTime startTime,
TimeSpan workingHours, DateTime expectedDueDate, string expectation)
{
CalendarPeriodCollectorFilter filter = new CalendarPeriodCollectorFilter();
filter.Months.Add(YearMonth.September); // only Januaries
filter.WeekDays.Add(DayOfWeek.Monday); //
filter.WeekDays.Add(DayOfWeek.Tuesday); //
filter.WeekDays.Add(DayOfWeek.Wednesday); //
filter.WeekDays.Add(DayOfWeek.Thursday); //
filter.WeekDays.Add(DayOfWeek.Friday); //
filter.CollectingHours.Add(new HourRange(9, 17)); // working hours
CalendarTimeRange testPeriod = new CalendarTimeRange(startTime, expectedDueDate);//new DateTime(2015, 9, 14, 9, 0, 0), new DateTime(2015, 9, 17, 18, 0, 0));
Console.WriteLine("Calendar period collector of period: " + testPeriod);
filter.ExcludePeriods.Add(new TimeBlock(new DateTime(2015, 9, 15, 00, 0, 0), new DateTime(2015, 9, 16, 0, 0, 0)));
CalendarPeriodCollector collector = new CalendarPeriodCollector(filter, testPeriod);
collector.CollectHours();
foreach (ITimePeriod period in collector.Periods)
{
Console.WriteLine("Period: " + period); // THIS WILL HELP A LOT!
}
var result = collector.Periods.GetTotalDuration(new TimeZoneDurationProvider(TimeZoneInfo.FindSystemTimeZoneById("UTC")));
Console.WriteLine(result);
//
}
这导致:
Calendar period collector of period: 14/09/2015 09:00:00 - 17/09/2015 15:59:59 | 3.06:59
Period: 14/09/2015 09:00:00 - 14/09/2015 16:59:59 | 0.07:59
Period: 16/09/2015 09:00:00 - 16/09/2015 16:59:59 | 0.07:59
15:59:59.9999998
因此,我注意到最后一个句点不见了。
如果你把课时的结束时间从下午4点改为下午6点(因此预计额外的一小时=24小时),那就差不多过去了。(您还需要对结果进行四舍五入)
因此,看起来总持续时间需要完全覆盖这些期间,不计算部分覆盖。您可以更改库的选项,也可以将工作日的每个小时添加为单独的收集小时(hacky)
希望这能让你更接近你需要的答案 请详细说明“计算不正确”的确切含义。给出输入、预期输出和实际输出的示例。谢谢。还要注意,这个特定的库在过去遇到过DST和时区问题。我在他们的变更日志中看到,v1.7.0对此做了一些调整,但在文档方面却很少。@MattJohnson源代码(Github)中的单元测试显示了预期。如果您运行单元测试,您将看到失败的单元测试。当然,我会在有时间时这样做。但总的来说,StackOverflow不赞成依靠外部站点来完成问题。请记住,StackOverflow的主要目的是创建对其他人有用的问题和答案的概要,而不仅仅是帮助您找到调试代码的人。如果问题既不简洁又不完整,那么它对其他人就没有多大帮助,也不会获得很多赞成票。对于StackOverflow,更好的做法是隔离一个失败的特定测试,并用尽可能少的代码重新生成它。请阅读:。然后有人可以回答你的代码有什么问题,或者库有什么问题。抱歉@Matt Johnson-看起来你已经在评论中找到了答案。我没有把它们全部展开去看。发布你的答案,Junto应该接受它而不是我的。那么它似乎是TimePeriodLibrary.NET中的一个bug?公共存储库中没有用于尝试发出请求的源代码。
[Test, TestCaseSource("LocalSource")]
public void SO_GetRemainingWorkingTimeWithHolidayShouldOnlyEnumerateWorkingTime(DateTime startTime,
TimeSpan workingHours, DateTime expectedDueDate, string expectation)
{
CalendarPeriodCollectorFilter filter = new CalendarPeriodCollectorFilter();
filter.Months.Add(YearMonth.September); // only Januaries
filter.WeekDays.Add(DayOfWeek.Monday); //
filter.WeekDays.Add(DayOfWeek.Tuesday); //
filter.WeekDays.Add(DayOfWeek.Wednesday); //
filter.WeekDays.Add(DayOfWeek.Thursday); //
filter.WeekDays.Add(DayOfWeek.Friday); //
filter.CollectingHours.Add(new HourRange(9, 17)); // working hours
CalendarTimeRange testPeriod = new CalendarTimeRange(startTime, expectedDueDate);//new DateTime(2015, 9, 14, 9, 0, 0), new DateTime(2015, 9, 17, 18, 0, 0));
Console.WriteLine("Calendar period collector of period: " + testPeriod);
filter.ExcludePeriods.Add(new TimeBlock(new DateTime(2015, 9, 15, 00, 0, 0), new DateTime(2015, 9, 16, 0, 0, 0)));
CalendarPeriodCollector collector = new CalendarPeriodCollector(filter, testPeriod);
collector.CollectHours();
foreach (ITimePeriod period in collector.Periods)
{
Console.WriteLine("Period: " + period); // THIS WILL HELP A LOT!
}
var result = collector.Periods.GetTotalDuration(new TimeZoneDurationProvider(TimeZoneInfo.FindSystemTimeZoneById("UTC")));
Console.WriteLine(result);
//
}
Calendar period collector of period: 14/09/2015 09:00:00 - 17/09/2015 15:59:59 | 3.06:59
Period: 14/09/2015 09:00:00 - 14/09/2015 16:59:59 | 0.07:59
Period: 16/09/2015 09:00:00 - 16/09/2015 16:59:59 | 0.07:59
15:59:59.9999998