Sezon urlopowy powoli dobiega końca, a do kolejnej dłuższej przerwy pozostało kilka tygodni. Ile dni roboczych konkretnie? Zwykle nie pracujemy 7 dni w tygodniu, zatem odpowiedzią wcale nie jest liczba tygodni razy 7. Na drodze stoją nam bowiem takie przeszkody jak weekendy i święta. Jak obliczyć liczbę dni roboczych między 2 datami w Power Query?
Gdy Excel bywa lepszy niż Power Query
Policzenie liczby dni roboczych w Excelu nie stanowi żadnego problemu – wystarczy funkcja DNI.ROBOCZE (ang. NETWORKDAYS), by zrobić to za jednym przeciągnięciem formuły. Jak z tym jest w Power Query? Niestety odpowiednik funkcji DNI.ROBOCZE trzeba stworzyć samodzielnie w języku M w Power Query. Skoro i tak musimy stworzyć własne rozwiązanie, warto uwzględnić w takiej funkcji świąteczne dni wolne od pracy dla Polski. Do dzieła!
Inspiracją do tego artykułu jest wpis Dominika Petri.
Algorytm funkcji DNI.ROBOCZE
Algorytm to wszystkie kroki, które powinien wykonać program (lub w tym przypadku funkcja), które są niezbędne, aby otrzymać pożądany efekt. W naszej funkcji zastosujemy ten sam algorytm, o którym pisze Dominik, ale dodatkowo uwzględnimy tabelę z wypisanymi datami świąt w latach 2019–2020. Zatem:
• Stworzymy listę wszystkich dat między datą początkową i końcową,
• Dodamy kolumnę z informacją o dniu tygodnia,
• Dodamy kolumnę z informacją, czy dany dzień był dniem świątecznym wolnym od pracy (nowość),
• Zaktualizujemy dni tygodnia, by dni świąteczne wyświetlały się jako szczególny dzień (nowość),
• Wyfiltrujemy soboty i niedziele oraz dni świąteczne,
• Liczba dni roboczych jest równa liczbie pozostałych dni na liście, czyli liczbie wierszy.
Liczba dni roboczych w Power Query krok po kroku
Zacznijmy od listy dat między datą początkową i końcową. W zakładce Strona główna > Dane zewnętrzne kliknij na strzałkę poniżej Pobierz dane i wybierz Puste zapytanie.
Otworzy się edytor Power Query wraz z możliwością wpisania formuły pierwszej funkcji. Na początek skorzystamy z funkcji List.Dates wpisując komendę =List.Dates
i klikając Enter.
Funkcja ta przyjmuje 3 argumenty: datę początkową, liczbę wierszy z datami, które mają się pokazać oraz jaki jest odstęp między kolejnymi datami. Wpiszemy przykładowe parametry i klikniemy Wywołaj. Załóżmy, że chcemy policzyć liczbę dni roboczych od 31 października 2019 w ciągu następnych 15 dni.
Efektem tego zapytania jest lista, którą należy przekonwertować do formatu tabeli. W zakładce Przekształć w Narzędziach do obsługi list kliknij Konwertuj > Do tabeli i skorzystaj z automatycznych stawień konwertera.
Dostaniesz tabelę, która jest gotowa do dalszej obróbki. Zwróć uwagę na kilka elementów. Po pierwsze (1) w pasku do wpisywania funkcji pokazał się kod, który tę tabelę wygenerował. Po drugie (2) po prawej stronie w pasku Ustawienia zapytania w zakładce Zastosowane kroki możesz śledzić, co po kolei było wykonywane w obróbce tabeli. Zauważ, że w funkcji (tekst w pasku na górze) odwołujemy się do efektu poprzedniego przekształcenia – wykorzystana funkcja Table.FromList korzysta ze zmiennej Źródła (3).
Następnie dodajmy kolumnę z dniami tygodnia. Kliknij Dodaj kolumnę > Z daty i godziny, a następnie strzałkę pod ikonką Data > Dzień > Dzień tygodnia.
Power Query numeruje dni od 0 do 6; 0 to pierwszy dzień tygodnia. Jak zidentyfikować, od którego z nich zaczyna się tydzień? Można kalendarzem, ale także ustawiając to jasno w kodzie. Do wyświetlonej w górnym pasku formuły dopisz po przecinku Day.Monday
zaraz za [Column1].
Twoim pierwszym dniem tygodnia wcale nie musi być poniedziałek. Gdy wpisywałeś formułę zapewne zauważyłeś, że jako początkowy można ustawić każdy dzień tygodnia. Zobacz też, w jaki sposób Power Query odwołuje się do wcześniej zastosowanych kroków; z użyciem krzyżyka # i wpisując nazwę w cudzysłów.
Dodajmy dni świąteczne w Polsce w latach 2019–2020. Z tej i tej strony skopiowałem i wkleiłem do Excela wszystkie świąteczne dni w Polsce.
Przez Power Query na Stronie głównej w Nowe zapytanie > Nowe Źródło > Excel wgrałem plik do Power BI.
Po kliknięciu OK nowa tabela znajdzie się po lewej stronie w bazie Zapytań. Wróć do tabeli z funkcją, automatycznie nazwaną Wywołano funkcję. Połączmy ją z tabelą z datami ze świętami scalaniem lewym zewnętrznym po dacie (więcej o rodzajach scalania tabel znajdziecie tu).
Rozpakuj dołączoną kolumnę klikając w znaczek w prawym górnym rogu dodanej kolumny. Odznacz datę – wystarczy sama nazwa święta dla lepszej orientacji – a następnie kliknij OK.
Stwórzmy nową kolumnę, w której dni świąteczne przyjmą wspólną wartość poza dniami tygodnia, np. 7. Posłużymy się dodawaniem kolumny warunkowej, którą można znaleźć w zakładce Dodaj kolumnę > Ogólne > Kolumna warunkowa. Jeśli przy dacie nie ma żadnego święta (jest NULL w kolumnie), ma przyjąć, że dzień jest standardowy. Jeśli jest to święto, zamienia dzień na 7.
Efektem zapytania jest kolumna Dni robocze.
Kliknij na strzałkę w prawym górnym rogu dodanej kolumny i odfiltruj sobotę, niedzielę oraz święta (wartości 5, 6 i 7) i wciśnij OK.
To tabela końcowa! Liczba wierszy, które pozostały to liczba dni roboczych między 31 października 2019 a 14.11.2019. Policzymy je funkcją Table.RowCount
Naciśnij ikonkę fx i przed #”Przefiltrowano wiersze” wpisz Table.RowCount tak jak na obrazku. Pamiętaj o nawiasach okrągłych!
Wciśnij Enter. Pojawi Ci się już nie tabela, ale sama liczba – liczba wierszy w tabeli, która pozostała.
Uwzględnimy jeszcze jeden parametr – jeśli data początkowa, od której chcemy policzyć liczbę dni jest późniejsza niż data końcowa, to różnica między datami jest liczbą ujemną. Zamień zatem kod zliczający wiersze na
= if Początek <= Koniec then Table.RowCount(#"Przefiltrowano wiersze") else Table.RowCount(#"Przefiltrowano wiersze") * (-1)
Ups, mamy błąd! Wynika on z użycia nazw, które nie są zdefiniowane – Początek i Koniec będą naszymi datami początkowymi i końcowymi w funkcji docelowej. Zatem napiszmy funkcję!
Zamiana przykładowej procedury na funkcję
Power Query i jego Zastosowane kroki w Ustawieniach zapytania działają trochę analogicznie jak nagrywanie makr w Excelu. Zapisują się Twoje kroki w obróbce danych, by potem nie dość, że móc do nich wrócić, to jeszcze bez znajomości języka M korzystać z gotowych wygenerowanych kodów przy przekształceniach na funkcje.
Pod ścieżką Strona główna > Zapytanie > Edytor zaawansowany ukryte jest pole do pisania poleceń w języku M. Zobaczysz wszystkie kroki, które wykonaliśmy, by dojść od wygenerowania ciągu dat do liczby dni roboczych i błędu w związku z nazwami.
Zacznijmy od definicji zmiennych, które będziemy wprowadzać do funkcji. W 11 linijce wykorzystujemy Początek i Koniec, które są datami początkowymi i końcowymi. Efektem działania funkcji jest zmienna o typie liczby – liczba dni roboczych. W pierwszej linijce wpisz zatem:
(Początek as date, Koniec as date) as number =>
i wciśnij Enter. Wprowadzimy jeszcze kilka zmian; rozbijemy Źródło na funkcję i wywołanie dat. Teraz
Źródło odwołuje się do wcześniej stworzonego zapytania. Wstawmy tam samą funkcję List.Dates, a linijkę niżej dopiszmy jej wywołanie według wzoru:
Źródło = List.Dates,#"Wywołanie dat" = Źródło(#date(2019, 10, 31), 15, #duration(1, 0, 0, 0)),
#"Przekonwertowane na tabelę" = Table.FromList(#"Wywołanie dat", Splitter.SplitByNothing(), null, null, ExtraValues.Error),
Kod powinien wyglądać tak:
Dlaczego zmieniamy aż 3 linijki? W każdej kolejnej odwołujemy się do wyników poprzedniego zapytania; dodając środkowe, trzeba zadbać o odpowiednie nazwy argumentów w następnej linijce. Na koniec pracy w kodzie zamieńmy stałe parametry wywołania funkcji List.Dates na te zależne od Początku i Końca. Zamień linijkę dotyczącą #”Wywołania dat” na:
#"Wywołanie dat" =
if Początek <= Koniec then
Źródło(Początek, Duration.Days(Koniec-Początek)+1, Duration.From(1))
else
Źródło(Koniec, Duration.Days(Początek-Koniec)+1,Duration.From(1)),
Gdy wciśniesz Gotowe, Twoim oczom ukaże się interfejs do wprowadzenia dat początkowych i końcowych – właśnie stworzyłeś autorską funkcję niestandardową! Zanim jednak przykładowo ją wywołamy, zmień jej nazwę. Po lewej stronie, w Zapytaniach, widnieje nazwa Wywołano funkcję. Możesz dowolnie zmieniać nazwę; ja nadam jej nazwę DniRoboczeBezSwiat.
Spróbujmy ją wywołać.
Działa! Spróbujmy teraz w prawdziwej tabeli z danymi. W Edytorze Power Query wybierz Narzędzia główne > Zapytaj > Zamknij i zastosuj, a następnie wgraj bazę szkoleniową ze sprzedażą w latach 2011–2014. Otwórzmy ją w Power Query, a następnie w Dodaj kolumnę > Ogólne > Wywołaj funkcję niestandardową jako Początek wprowadź Datę zamówienia, a jako Koniec Datę wysyłki. Kliknij OK.
Funkcja bez problemu policzy liczbę dni roboczych między datami w kolumnach.
Szablon funkcji do pobrania w Power Query w Excelu
Tu możesz pobrać plik Excel z funkcją Power Query do liczenia dni roboczych oraz plik z dniami świątecznymi (podmień jego ścieżkę w kroku Źródło).
Wpisuje daty 2021-11-03 do 2021-11-30 i otrzymuje wynik 20, po uprzednim dopisaniu świat za 2021 rok. Powinna być liczba 19?
Przepraszam, wszystko działa. Trzeba również kolumnę z Nazwą uzupełnić.
Dzięki za potwierdzenie.
Cześć,
Funkcja działa ale po próbie wykorzystania jej w innej tabeli jako nową kolumnę wyskakuję błąd jak poniżej:
Expression.Error: Nie możemy przekonwertować wartości „[Function]” na typ Function.
Szczegóły:
Value=[Function]
Type=[Type]
Czym to może być spowodowane?
Hej Michał, podeślij plik na maila, bo bez niego trudno udzielić pomocy.
Fajny pomysł tylko tak jak koledze wyżej po wywołaniu funkcji ukazuje mi się
„Wystąpił błąd w zapytaniu „”. Expression.Error: Nie możemy przekonwertować wartości typu Function na typ List.
Szczegóły:
Value=[Function]
Type=[Type]”
gdzie może być problem?
Podeślij plik na kontakt(at)skuteczneraporty.pl .
udało się pomóc?
Mam ten sam problem, jednak nie mogę wysłać pliku (dane wrażliwe)
odpowiem sam sobie 🙂 był błąd w moim kodzie nie pojawiło się #”Wywołanie dat” tylko było jako Zródło, podmiana w jednej linii naprawiła błąd.
Dzięki, Alek.