【问题标题】:Is there an optimized way of getting business weeks between two dates?有没有一种优化的方式来获得两个日期之间的工作周数?
【发布时间】:2015-07-14 08:37:05
【问题描述】:

只是想知道是否有更优化和/或更简洁的方式(例如使用 LINQ)来编写我在下面获得的两个日期之间的工作周日期范围列表?

这是我目前拥有的..

// Some storage
public class Bucket
{
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
}

// Other code removed for brevity ...

DateTime start = new DateTime(2015, 7, 1);
DateTime end = new DateTime(2015, 9, 1);

DayOfWeek firstDayOfWeek = DayOfWeek.Monday;
DayOfWeek lastDayOfWeek = DayOfWeek.Friday;

var buckets = new List<Bucket>();
var currentDate = start;
DateTime startOfBucket = currentDate;
DateTime endOfBucket = currentDate;
while (currentDate <= end)
{
    var currentDayOfWeek = currentDate.DayOfWeek;

    // Skip days outside the business week
    if (currentDayOfWeek >= firstDayOfWeek && currentDayOfWeek <= lastDayOfWeek)
    {
        if (currentDayOfWeek == firstDayOfWeek)
        {
            // Start a new bucket
            startOfBucket = currentDate;
        }

        if ((currentDayOfWeek == lastDayOfWeek) || (currentDate == end))
        {
            // End of bucket
            endOfBucket = currentDate;

            // Create bucket
            buckets.Add(new Bucket() 
            { 
                StartDate = startOfBucket, 
                EndDate = endOfBucket 
            });

        }
    }

    currentDate = currentDate.AddDays(1);
}

这会给我以下日期范围...

  • 开始:2015 年 7 月 1 日结束:2015 年 7 月 3 日
  • 开始:2015 年 7 月 6 日结束:2015 年 7 月 10 日
  • 开始:2015 年 7 月 13 日结束:2015 年 7 月 17 日
  • 开始:2015 年 7 月 20 日结束:2015 年 7 月 24 日
  • 开始:2015 年 7 月 27 日结束:2015 年 7 月 31 日
  • 开始:2015 年 8 月 3 日结束:2015 年 8 月 7 日
  • 开始:2015 年 8 月 10 日结束:2015 年 8 月 14 日
  • 开始:2015 年 8 月 17 日结束:2015 年 8 月 21 日
  • 开始:2015 年 8 月 24 日结束:2015 年 8 月 28 日
  • 开始:2015 年 8 月 31 日结束:2015 年 9 月 1 日

注意第一周和最后一周故意不是整周(它们遵守给定的日期范围)。

编辑 here 提供的解决方案给出了两个日期之间的天数,但我有兴趣获取日期范围的集合。

另外,我不需要考虑任何假期。

谢谢,

【问题讨论】:

  • 公共假期你想做什么?工作周并不总是周一到周五的文化?
  • @serhiyb 我特别喜欢 José Silva 的回答
  • @RoyT。他的答案仍然每天都在迭代,而接受/赞成的答案确实提供了 O(1) 中的答案。
  • @JonSkeet Hi Jon .. 这是一个基本范围,因此不考虑任何假期。谢谢

标签: c# linq date


【解决方案1】:

使用 linq 非常方便

var startDate = new DateTime(2015, 7, 1);
var endDate = new DateTime(2015, 9, 1);
var workDates = Enumerable.Range(0, (int)(endDate - startDate).TotalDays + 1)
    .Select(i => startDate.AddDays(i))
    .Where(date => (date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday))
    .Select(i => i);


var display = workDates
    .GroupAdjacentBy((x, y) => x.AddDays(1) == y)
    .Select(g => string.Format("Start: {0:dd/MMM/yyyy} End: {1:dd/MMM/yyyy}", g.First(), g.Last()));

使用扩展方法GroupAdjacentBy&lt;T&gt;

public static class IEnumerableExtension
{
    public static IEnumerable<IEnumerable<T>> GroupAdjacentBy<T>(
        this IEnumerable<T> source, Func<T, T, bool> predicate)
    {
        using (var e = source.GetEnumerator())
        {
            if (e.MoveNext())
            {
                var list = new List<T> { e.Current };
                var pred = e.Current;
                while (e.MoveNext())
                {
                    if (predicate(pred, e.Current))
                    {
                        list.Add(e.Current);
                    }
                    else
                    {
                        yield return list;
                        list = new List<T> { e.Current };
                    }
                    pred = e.Current;
                }
                yield return list;
            }
        }
    }
}

Fiddle

【讨论】:

  • 谢谢@Eric 我喜欢这个解决方案。我在上面添加了扩展,因为我花了一分钟才意识到它不是 .Net 扩展。
  • @GavinSutherland 让我为其他人补充答案
【解决方案2】:

这是基于Eric's accepted answer 所以请给他任何支持。我刚刚修改了他的解决方案,以处理可能长达 7 天的工作周以及可能结束一个周末的工作周。

var startDate = new DateTime(2015, 7, 1);
var endDate = new DateTime(2015, 9, 1);

DayOfWeek firstDayOfWeek = DayOfWeek.Monday;
DayOfWeek lastDayOfWeek = DayOfWeek.Friday;

var workDates = Enumerable.Range(0, (int)(endDate - startDate).TotalDays + 1)
            .Select(i => startDate.AddDays(i))
            .Where(date => 
                // Normal work weeks where first day of week is before last (numerically) e.g. Monday -> Friday or Sunday -> Saturday
                (firstDayOfWeek < lastDayOfWeek && date.DayOfWeek >= firstDayOfWeek && date.DayOfWeek <= lastDayOfWeek) ||
                // Cater for business weeks whose start and end dates wrap over the weekend e.g. Thursday -> Tuesday
                (lastDayOfWeek < firstDayOfWeek && (date.DayOfWeek >= firstDayOfWeek || date.DayOfWeek <= lastDayOfWeek)))
            .Select(i => i);

var display = workDates
            .GroupAdjacentBy((x, y) => x.AddDays(1) == y && !(x.DayOfWeek == lastDayOfWeek && y.DayOfWeek == firstDayOfWeek))
            .Select(g => string.Format("Start: {0:dd/MMM/yyyy} End: {1:dd/MMM/yyyy}", g.First(), g.Last())); 

【讨论】:

    猜你喜欢
    • 2020-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 2011-09-18
    • 2012-04-15
    相关资源
    最近更新 更多