计算“工作时间”使用TimePeriod.NET'的CalendarPeriodCollector会得到意想不到

本文关键字:CalendarPeriodCollector 意想不到 NET 时间 工作 工作时间 TimePeriod 使用 计算 | 更新日期: 2023-09-27 18:13:42

我正在计算服务水平协议的到期日,同时,我还需要反向计算另一个方向的服务水平协议。

我一直在努力计算"工作时间"(即在一组天内工作的时间),并决定使用一个名为TimePeriodLibrary的第三方库。. NET用于任务。我需要能够做两件事:

  • 给定起始DateTimeTimeSpan,您应该接收到服务水平协议日期到期(日期到期)的DateTime
  • 给定开始DateTime和结束DateTime,您应该收到一个TimeSpan,该服务水平协议应该花费多长时间。

所有源代码(测试项目在GitHub上)。我有一个ServiceLevelManager类做所有的工作。它需要WorkDaysHolidayPeriods的列表,以便计算出哪些时间可以工作。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);
        }
    }
}

失败的单元测试提取如下:

[TestFixture]
public class ServicePlannerManagerTest
{
        [Test, TestCaseSource("LocalSource")]
    public void GetRemainingWorkingTimeWithHolidayShouldOnlyEnumerateWorkingTime(DateTime startTime, TimeSpan workingHours, DateTime expectedDueDate, string expectation)
    {
        // Arrange
        var workDays = new List<WorkDay>
        { 
            new WorkDay(DayOfWeek.Monday, new DateTime(1, 1, 1, 9, 0, 0), new DateTime(1, 1, 1, 17, 0, 0)),
            new WorkDay(DayOfWeek.Tuesday, new DateTime(1, 1, 1, 9, 0, 0), new DateTime(1, 1, 1, 17, 0, 0)),
            new WorkDay(DayOfWeek.Wednesday, new DateTime(1, 1, 1, 9, 0, 0), new DateTime(1, 1, 1, 17, 0, 0)),
            new WorkDay(DayOfWeek.Thursday, new DateTime(1, 1, 1, 9, 0, 0), new DateTime(1, 1, 1, 17, 0, 0)),
            new WorkDay(DayOfWeek.Friday, new DateTime(1, 1, 1, 9, 0, 0), new DateTime(1, 1, 1, 17, 0, 0)),
        };
        var holidayPeriods = new List<HolidayPeriod>
        { 
            new HolidayPeriod(new DateTime(2015, 9, 15, 00, 0, 0), new DateTime(2015, 9, 16, 0, 0, 0))
        };
        var service = new ServicePlannerManager(workDays, holidayPeriods);
        // Act
        var result = service.GetRemainingWorkingTime(startTime, expectedDueDate);
        // Assert - 
        Assert.AreEqual(workingHours.TotalHours, result.TotalHours, expectation);
    }
    protected IEnumerable LocalSource()
    {
        yield return
            new TestCaseData(
                new DateTime(2015, 9, 14, 9, 0, 0),
                new TimeSpan(23, 0, 0),
                new DateTime(2015, 9, 17, 16, 0, 0),
                    "5. Expected 23 hours of working time to end on the 17/09/2015 16:00. Monday to Thursday evening. Just short of 3 full working days by one hour. Tuesday is holiday.");
    }
}

这个测试的输出是

5. Expected 23 hours of working time to end on the 17/09/2015 16:00. Monday to Thursday evening. Just short of 3 full working days by one hour. Tuesday is holiday.
Expected: 23.0d
But was:  15.999999999944444d

我想知道我是否错误地使用了收集器,或者收集器是否有错误。

计算“工作时间”使用TimePeriod.NET'的CalendarPeriodCollector会得到意想不到

这个库看起来很适合解决一个熟悉的问题。

最好的方法是输出周期集合中的周期,以帮助您调试问题。

我已经重写了您的测试,以使用他们文档中的示例中的基本类型:

        [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)

希望这能让你更接近你需要的答案!

相关文章:
  • 没有找到相关文章