2015-07-14 4 views
2

Просто интересно, есть ли более оптимизированный и/или более быстрый способ (используя 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/Июль/2015 Конец: 03/Июль/2015
  • Начало: 06/июль/2015 Конец: 10/июль/2015
  • Старт: 13/июль/2015 Конец: 17/июль/2015
  • Начало: 20/июль/2015 Конец: 24/июль/2 015
  • Начало: 27/Июль/2015 Конец: 31/Июль/2015
  • Начало: 03/Август/2015 Конец: 07/Август/2015
  • Начало: 10/Август/2015 Окончание: 14/Август/2015
  • Начало: 17/август/2015 Конец: 21/август/2015
  • Начало: 24/август/2015 Конец: 28/август/2015
  • Начало: 31/август/2015 Конец: 01/Сентябрь/2015 год

NB Первая и последняя недели целенаправленно не полные недели (они соответствуют заданному дате).

Редактировать Решение, предлагаемое here дает количество дней между двумя датами, но я заинтересован в получении коллекции диапазонов дат.

Кроме того, мне не нужно учитывать любые праздники.

Спасибо,

+0

Что бы вы хотели сделать в отношении государственных праздников? Культуры, где рабочая неделя не всегда с понедельника по пятницу? –

+1

Взгляните на http://stackoverflow.com/questions/1617049/calculate-the-number-of-business-days-between-two-dates – serhiyb

+0

@serhiyb Мне особенно нравится ответ Хосе Сильва –

ответ

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

+0

Thanks @Eric Мне нравится это решение. Я добавил расширение выше, так как мне потребовалась минута, чтобы понять, что это не расширение .Net. –

+0

@GavinSutherland Позвольте мне добавить к ответам другие – Eric

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())); 
Смежные вопросы