Número de dias úteis entre datas usando Power Query

Quando conheci o Power Query em 2015, me apaixonei pela linguagem M. Muito dá para se fazer usando o M para tratar as fonte de dados.

Uma das funções que não existe de forma nativa na linguagem M é a contagem de dias úteis, desconsiderando os feriados também. Com isso, escrevi a função fnNumberWorkDay.

Sobre a função fnNumberWorkDay

Esta função retorna a quantidade de dias úteis com base em uma data de referência (startDate), considerando uma lista de feriados (opcional) e a possibilidade de ser inclusivo com a data de referência (startDate) na contagem. Por padrão não é inclusivo.

No link a seguir, possui o código completo para poder usar dentro do Power Query. https://github.com/pietrofarias/PatternsM/blob/main/fnNumberWorkDay.pq

Na função é usada quartro parâmetros:

  • StartDate → Informar a data inicial
  • EndDate → Informar a data final
  • InclusiveStartDate (Opcional) → Se a contagem deve considerar (inclusivo) o primeiro dia
  • HolidayDatesList (Opcional) → Uma lista com as datas no qual devem ser consideradas como dias não úteis, por exemplo, feriados.

Exemplos do uso da função

Retornar a quantidade de dias úteis, desconsiderando uma os feriados da lista HolidayDatesQuery (lista de datas) e os finais de semana

= NumberWorkDay( #date(2020,12,31), #date(2020,1,7), false, HolidayDatesQuery )

Resultado → 4


Retornar a quantidade de dias úteis, desconsiderando apenas o final de semana

LastOrNextWorkDay(#date(2020,12,31), #date(2020,1,6), false) Resultado → 4


Retornar a quantidade de dias úteis, desconsiderando apenas o final de semana e incluindo a data de referência na contagem

LastOrNextWorkDay(#date(2020,12,31), #date(2020,1,5), false) Resultado → 4


Retornar a quantidade de dias úteis, desconsiderando apenas o final de semana, incluindo a data de referência na contagem, mas a data de referência é um sábado

LastOrNextWorkDay(#date(2021,1,2), #date(2020,1,7), true) Resultado → 4


Como usar a função dentro do Powwer Query

Eu coloquei no artigo "Como usar funções personalizadas de outros desenvolvedores no Power Query", o passo a passo para poder colar o código abaixo.

// Developer: Pietro Farias
// analistax@email.com
let
    fn = (startDate as date, EndDate as date, optional InclusiveStartDate as nullable logical, optional HolidayDatesList as list) /*as number*/  =>
        let
            HolidayDates = if HolidayDatesList is null then {} else HolidayDatesList,
            InclusiveDay = if InclusiveStartDate is null then false else InclusiveStartDate,
            DurationDays = Duration.Days(EndDate - startDate),
            GenerateList = 
                List.Buffer(
                    List.Generate( () => 
                        [
                            Counter = 0,
                            StartDate = Date.From(startDate),
                            Holiday = List.MatchesAny(HolidayDates, each Date.From(_) = StartDate),
                            Run = Counter <=  Number.Abs(DurationDays)
                        ],
                        
                        each [Run] = true and [StartDate] <= EndDate,
                        each [
                            StartDate = Date.AddDays([StartDate], 1),
                            Holiday = List.MatchesAny(HolidayDates, each Date.From(_) = StartDate),
                            Counter = 
                                if  Date.DayOfWeek(StartDate, Day.Saturday) > 1
                                    and not Holiday 
                                then [Counter] + 1
                                else [Counter], 
                            Run = Counter <=  Number.Abs(DurationDays)
                        ],
                        each [StartDate]
                    )
                ),
            RemoveDateWeekndayAndHoliday = 
                List.Select( 
                    GenerateList, 
                    each 
                        not (
                            let 
                                DateRef = _,
                                IsWeekDay = Date.DayOfWeek(DateRef , Day.Saturday) > 1,
                                IsHoliday = 
                                    if HolidayDates is null 
                                    then false 
                                    else List.MatchesAny(HolidayDates, each Date.From(_) = DateRef)
                            in IsWeekDay = false or IsHoliday = true
                        ) and (
                            if InclusiveDay then _ >= startDate else _ > startDate
                        )
                ),
            Result = List.Count(RemoveDateWeekndayAndHoliday)
        in
            Result,
    fnType = type function (
        startDate as date, 
        EndDate as date, 
        optional InclusiveStartDate as (type logical meta [ Documentation.AllowedValues={true,false}]), 
        optional HolidayDatesList as list
    ) as date meta 
        [
            Documentation.Name = "fnNumberWorkDay",
            Documentation.LongDescription = "Descriptions in pt-BR: Estão função retorna a quantidade de dias úteis com base em uma data de referência (startDate), considerando uma lista de feriados (opcional) e a possibilidade de se inclusivo com a data de referência (startDate) na contagem. Por padrão não é inclusivo.",
            Documentation.Examples =
            {
                [
                    Description = "Esta função retorna a quantidade de dias úteis, desconsiderando uma os feriados da lista HolidayDatesQuery (lista de datas) e os finais de semana",
                    Code = "NumberWorkDay(#date(2020,12,31), #date(2020,1,7), false, HolidayDatesQuery)",
                    Result = "4"
                ],
                [
                    Description = "Esta função retorna a quantidade de dias úteis, desconsiderando apenas o final de semana",
                    Code = "LastOrNextWorkDay(#date(2020,12,31), #date(2020,1,6), false)",
                    Result = "4"
                ],
                [
                    Description = "Esta função retorna a quantidade de dias úteis, desconsiderando apenas o final de semana e incluindo a data de referência na contagem",
                    Code = "LastOrNextWorkDay(#date(2020,12,31), #date(2020,1,5), false)",
                    Result = "4"
                ],
                [
                    Description = "Esta função retorna a quantidade de dias úteis, desconsiderando apenas o final de semana, incluindo a data de referência na contagem, mas a data de referência é um sábado",
                    Code = "LastOrNextWorkDay(#date(2021,1,2), #date(2020,1,7), true)",
                    Result = "4"
                ]
            }

        ]
in
    Value.ReplaceType(fn, fnType)

Muito bom. Eu estou usando a função NETWORKDAYS.

No DAX tem a função NETWORKDAYS. https://learn.microsoft.com/pt-br/dax/networkdays-dax Infelizmente de forma nativa não tem no Power Query. A ideia é ter a possibilidade de usar o mesmo objetivo no ETL com o Power Query