是否有优化的方式在两个日期之间获得营业周?

时间:2015-07-14 08:37:06

标签: c# linq date

只是想知道是否有更优化和/或更简洁的方式(使用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);
}

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

  • 开始时间:01 / Jul / 2015结束:03 / Jul / 2015
  • 开始时间:06 / Jul / 2015结束:10 / Jul / 2015
  • 开始时间:2015年7月13日结束:2015年7月17日
  • 开始时间:2015年7月20日结束时间:2015年7月24日
  • 开始时间:2015年7月27日结束时间:2015年7月31日
  • 开始时间:03 / Aug / 2015结束:07 / Aug / 2015
  • 开始时间:2015年8月10日结束时间:2015年8月14日
  • 开始时间:2015年8月17日结束时间:2015年8月21日
  • 开始时间:2015年8月24日结束:2015年8月28日
  • 开始时间:2015年8月31日结束时间:2015年9月1日

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

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

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

谢谢,

2 个答案:

答案 0 :(得分: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<T>

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

答案 1 :(得分:0)

这是基于Eric's accepted answer所以请给他任何upvote。我刚刚修改了他的解决方案来处理可能长达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()));