2015-07-14 1 views
2

Je me demandais s'il y avait une manière plus optimisée et/ou plus propre (en utilisant LINQ par exemple) d'écrire ce que j'ai ci-dessous pour obtenir une liste de plages de dates de semaine d'affaires entre deux dates?Existe-t-il un moyen optimisé d'obtenir des semaines commerciales entre deux dates?

C'est ce que j'ai actuellement ..

// 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); 
} 

Et cela me donnera les plages de dates suivantes ...

  • Début: 01/juillet/2015 Fin: 03/Jul/2015
  • Début: 06/juillet/2015 Fin: 10/Jul/2015
  • Début: 13/Jul/2015 Fin: 17/Jul/2015
  • Début: 20/juillet/2015 Fin: 24/Jul/2 015
  • Début: 27/juillet/2015 Fin: 31/Jul/2015
  • Début: 03/août/2015 Fin: 07/août/2015
  • Début: 10/août/2015 Fin: 14/Aug/2015
  • Début: 17/août/2015 Fin: 21/août/2015
  • Début: 24/août/2015 Fin: 28/août/2015
  • Début: 31/août/2015 Fin: 01/Sept/2015

NB La première et la dernière semaine sont délibérément des semaines incomplètes (elles respectent la période donnée).

Modifier La solution fournie here donne le nombre de jours entre les deux dates mais je suis intéressé à obtenir la collection de plages de dates.

De plus, je n'ai pas besoin de prendre en compte les vacances.

Merci,

+0

Que voudriez-vous faire au sujet des jours fériés? Cultures où la semaine de travail n'est pas toujours du lundi au vendredi? –

+1

Jetez un coup d'oeil à http://stackoverflow.com/questions/1617049/calculer-le-numéro-du-business-jours-dans-two-dates – serhiyb

+0

@serhiyb J'aime particulièrement la réponse de José Silva –

Répondre

1

Il est tout à fait à portée de main en utilisant 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())); 

Avec la méthode d'extension 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

Merci @Eric J'aime cette solution. J'ai ajouté l'extension ci-dessus car il m'a fallu une minute pour réaliser que ce n'était pas une extension .Net. –

+0

@GavinSutherland Permettez-moi d'ajouter à la réponse pour les autres – Eric

0

Ceci est basé sur Eric's accepted answer donc s'il vous plaît lui donner une upvote . Je viens de modifier sa solution pour gérer les semaines d'affaires qui pourraient durer 7 jours et aussi pour une semaine qui pourrait envelopper un week-end.

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()));