2011-12-19 17 views
15

Piszę eksportera Excela dla tworzonej przeze mnie aplikacji, którą mam, i mam pytanie dotyczące grupowania LINQ w C#.Jak pogrupować daty według tygodni?

Zasadniczo nowa klasa eksportera programu Excel ma dwie daty. Następnie klasa pobiera wszystkie przesyłki między tym zakresem dat.

Jako część tego eksportera muszę umieć grupować daty na tygodnie i uzyskać wartości dla tego tygodnia. Na przykład, jeśli mam dane 07/12/2011 i 22.12.2011 r. (Format dd/MM/rrrr), muszę pogrupować wszystkie przesyłki między nimi na tygodnie (każdy tydzień zaczyna się od niedzieli). Idealny wynik w powyższych datach to:

Week 1: (consignments between 04/12/2011 and 10/12/2011) 
Week 2: (consignments between 11/12/2011 and 17/12/2011) 
Week 3: (consignments between 18/11/2011 and 24/12/2011) 

Jakieś pomysły?

Odpowiedz

28

Podstawowe pytanie brzmi: jak zaprojektować instancję DateTime na wartość z roku na rok. Można to zrobić, dzwoniąc pod numer Calendar.GetWeekOfYear. Więc zdefiniuj rzutowanie:

Func<DateTime, int> weekProjector = 
    d => CultureInfo.CurrentCulture.Calendar.GetWeekOfYear(
     d, 
     CalendarWeekRule.FirstFourDayWeek, 
     DayOfWeek.Sunday); 

Możesz dokładnie skonfigurować, jak określa się "numer tygodnia", poprawiając parametry w wywołaniu metody. Możesz także zdecydować o zdefiniowaniu projekcji jako np. metoda rozszerzenia, jeśli wolisz; to nie zmienia istoty kodu. W każdym razie, jesteś gotowy do grupy przez tydzień:

var consignmentsByWeek = from con in consignments 
         group con by weekProjector(con.Date); 

Jeśli chcemy także, aby ograniczyć wyjście do partii towarów między dwoma dat, wystarczy dodać odpowiedni where klauzuli; logika grupowania się nie zmienia.

21

Wahający się, chociaż nie zgadzam się z tak cenionym odbiorcą, uważam, że przyjęta tu odpowiedź jest błędna, a to nie jest kwestia zasadniczej wartości tygodnia.

GetWeekOfYear(), a koncepcja w ogólności polega na przypisywaniu wartości indeksu do tygodni w ciągu roku, zgodnie z ustalonym standardem. Nie nadaje się do umieszczania dat w grupach siedmiu sąsiednich dni, ponieważ wierzę, że pytający wymaga.

Nie tylko użyjemy funkcji GetWeekOfYear() jako proponowanego wyniku w grupach o długości mniejszej niż siedem dni pod koniec wielu lat, ale jeszcze gorzej, ponieważ różne standardy obsługiwane przez GetWeekOfYear() często będą przyporządkowywać pierwsze dni rok do ostatniego tygodnia poprzedniego roku, a mimo to wynik GetWeekOfYear() zawiera tylko całkowity indeks tygodniowy bez odniesienia do skojarzonego roku, grupowanie przez new { Year = date.Year, weekProjector(date) } lub date.Year + "-" + weekProjector(date) w roku pytającego obejrzy 1 stycznia 2011 r. zgrupowane w dzień świąteczny do sylwestra dwanaście miesięcy później tego samego roku.

Więc chciałbym twierdzić, że oryginalne pytanie jest zasadniczo jednym z wystających nie do tygodnia wartości roku, ale do tygodniu wszystkich wartości czasu „tydzień począwszy Y/M/D”, możesz powiedzieć, więc grupowanie musi być dokonana jedynie przez pierwszy dzień tygodnia, czyli (zakładając, że jesteś zadowolony domyślne do niedzieli) po prostu:

group by date.AddDays(-(int)date.DayOfWeek) 
+0

przyszedłem na to pytanie, ponieważ miałem już kod, który wyglądał bardzo podobnie zaakceptowana odpowiedź. Nie podobało mi się to z tych samych powodów, o których mówisz. Ten kod jest prostszy i ułatwia segmentację dni. Dzięki! Możesz również posegmentować inny dzień tygodnia (np. Poniedziałki), dodając ten dzień do tego wyniku. – user1304444

+0

Zmodyfiowałem sugestię w odpowiedzi (dobra odpowiedź btw), aby "przyciągnąć" datetime do najbliższego okresu. 'group by date.AddDays (((int) date.DayOfWeek) <4? (- (int) date.DayOfWeek): (- (int) date.DayOfWeek + 7))' – g2server

1

Oprócz Jon's odpowiedź można uzyskać daty pierwszego dzień w tygodniu, a następnie grupuj według tej daty.

Aby uzyskać datę pierwszego dnia tygodnia. można użyć tego kodu:

public static class DateTimeExtensions 
{ 
    public static DateTime StartOfWeek(this DateTime dt, DayOfWeek startOfWeek) 
    { 
     int diff = dt.DayOfWeek - startOfWeek; 
     if (diff < 0) 
     { 
      diff += 7; 
     } 
     return dt.AddDays(-1 * diff).Date; 
    } 
} 

następnie można grupować według pierwszego dnia tygodnia tak:

var consignmentsByWeek = from con in consignments 
         group con by con.Datedate.StartOfWeek(DayOfWeek.Monday); 
Powiązane problemy