使用Nodatime排除期间的日期

时间:2013-11-18 10:41:41

标签: c# nodatime

我正在尝试计算两个LocalDateTime值之间的时间量并排除特定日期(在此示例中为银行假日)。

var bankHolidays = new[] { new LocalDate(2013, 12, 25), new LocalDate(2013, 12, 26) };
var localDateTime1 = new LocalDateTime(2013, 11, 18, 10, 30);
var localDateTime2 = new LocalDateTime(2013, 12, 29, 10, 15);

var differenceBetween = Period.Between(localDateTime1, localDateTime2, PeriodUnits.Days | PeriodUnits.HourMinuteSecond);

differenceBetween值显示两个日期之间的天数/小时/分钟/秒,如您所料。

我可以检查开始日期的每一天,看看bankHolidays集合是否包含该日期,例如

var bankHolidays = new[] { new LocalDate(2013, 12, 25), new LocalDate(2013, 12, 26) };
var localDateTime1 = new LocalDateTime(2013, 11, 18, 10, 30);
var localDateTime2 = new LocalDateTime(2013, 12, 29, 10, 15);

var differenceBetween = Period.Between(localDateTime1, localDateTime2, PeriodUnits.Days | PeriodUnits.HourMinuteSecond);

var london = DateTimeZoneProviders.Tzdb["Europe/London"];

for (var i = 1; i < differenceBetween.Days; ++i)
{
    var x = localDateTime1.InZoneStrictly(london) + Duration.FromStandardDays(i);

    if (bankHolidays.Any(date => date == x.Date))
    {
        //subtract one day for the period.
    }
}

我觉得我错过了一些显而易见的方法,应该有一种更简单的方法,是否有更简单的方法可以找到两个日期之间的时间段而不包括某些日期?

我也需要在这个排除中包括周末,显而易见的方式似乎是在检查银行假期的同时检查周末的一周,这似乎不是处理它的最佳/正确方法

2 个答案:

答案 0 :(得分:4)

  

我觉得我错过了一些显而易见的方法,应该有一种更简单的方法,是否有更简单的方法可以找到两个日期之间的时间段而不包括某些日期?

嗯,计算日期至今范围内的银行假日数量相对容易:

  • 按时间顺序对所有银行假期进行排序
  • 使用二进制搜索找出开始日期在集合中的位置
  • 使用二进制搜索找出结束日期将在集合中的位置
  • 从另一个索引中减去一个索引以查找该范围内的条目数
  • 使用Period.Between完成整个时段,因为您已经在做
  • 从范围
  • 中的总天数中减去范围内的条目数

令人讨厌的是考虑到开始和/或结束日期可能是银行假日。有一个很大的潜在的错误,但有一套好的单元测试应该没问题。

或者,如果您的银行假期相对较少,您可以使用:

var period = Period.Between(start, end,
                            PeriodUnits.Days | PeriodUnits.HourMinuteSecond);
var holidayCount = holidays.Count(x => x >= start && x <= end);
period = period - Period.FromDays(holidayCount);

答案 1 :(得分:0)

只需使用TimeSpan即可获得差异,所有时间都在您当前的当地时区:

var bankHolidays = new[] { new DateTime(2013, 12, 25), new DateTime(2013, 12, 26) };
var localDateTime1 = new DateTime(2013, 11, 18, 10, 30, 0);
var localDateTime2 = new DateTime(2013, 12, 29, 10, 15, 0);
var span = localDateTime2 - localDateTime1;
var holidays = bankHolidays[1] - bankHolidays[0];
var duration = span-holidays;

现在duration是您在localDateTime1localDateTime2之间经过的时间。 如果您想通过bankHolidays排除两个日期,则可以轻松修改上述操作。

您可以使用额外的方法进行此操作:

public static TimeSpan GetPeriod(DateTime start, DateTime end, params DateTime[] exclude)
{
    var span = end - start;
    if (exclude == null) return span;
    span = exclude.Where(d => d >= start && d <= end)
    .Aggregate(span, (current, date) => current.Subtract(new TimeSpan(1, 0, 0, 0)));
    return span;
}

现在你可以使用它:

var duration = GetPeriod(localDateTime1, localDateTime2, bankHolidays);