Acerca de los rangos de fecha de cálculo en DAX

Al desarrollar medidas de inteligencia de tiempo con Power BI o en tela en modelos semánticos, puede ser necesario crear un rango de fecha para calcular el resultado para un marco de tiempo específico.

Para ser precisos, casi todo el tiempo funciona Dax Cree una lista de fechas para un rango de fechas.

Pero a veces debemos crear un rango de fechas personalizado debido a requisitos específicos.

DAX nos ofrece dos funciones para esta tarea:

Ambas funciones toman una fecha de inicio como parámetro.
Pero para la fecha de finalización, el comportamiento es diferente.

Mientras DATESINPERIOD() Toma intervalos (días, meses, cuartos, años), DATESBETWEEN() Toma una fecha especificada utilizada como la fecha de finalización.

En contraste, DATEADD() Utiliza el contexto del filtro actual para obtener la fecha de inicio y para calcular la fecha de finalización.

Pero queremos pasar una fecha de inicio, que puede diferir de las fecha (s) en el contexto del filtro actual.

Esto es cuando una de las funciones mencionadas anteriormente entra en juego.

Al final de este artículo, le mostraré un ejemplo práctico utilizando las técnicas que se muestran aquí.

Herramientas y escenario

Como en muchos otros artículos, uso DAX Studio para escribir consultas DAX y analizar los resultados.

Si no está familiarizado con escribir consultas DAX, lea mi pieza sobre cómo aprender a escribir tales consultas:

Esta vez, uso el modelo de datos solo para la tabla de fechas.

Quiero calcular un rango de fechas a partir del 5 de mayo. 2025 y 25 días o 2 meses en el futuro.

Para establecer la fecha de inicio, uso esta expresión:

DEFINE
    VAR StartDate = "2025-05-05"

EVALUATE
       { StartDate }

Este es el resultado en DAX Studio:

Figura 1 – Consulta y resultado en Dax Studio (figura del autor)

Defino una variable y asigno el resultado de la expresión de fecha para las consultas posteriores.

Otra forma de definir la fecha de inicio es crear un valor de fecha usando DATE(2025, 05, 05).

El resultado será el mismo.

La diferencia entre estos dos enfoques es que la primera devuelve una cadena, pero la segunda devuelve una fecha adecuada.

Las funciones DAX utilizadas aquí pueden funcionar con ambas.

Usar DatesInperiod ()

Empecemos con DATEINPERIOD().

Usaré esta función para obtener una cadena de rango de fecha desde la fecha de inicio y 25 días al futuro:

DEFINE
    VAR StartDate = "2025-05-05"
    
EVALUATE
    DATESINPERIOD('Date'[Date]
                    ,StartDate
                    ,25
                    ,DAY)

El resultado es una tabla con 25 filas para los días a partir del 05 de mayo de 2025 al 29 de mayo de 2025:

Figura 2 – 25 días calculado con DatesInperiod () (Figura del autor)

Ahora, cambiemos ligeramente la consulta para obtener una lista de todas las fechas desde la fecha de inicio hasta 2 meses en el futuro:

DEFINE
    VAR StartDate = "2025-05-05"
    
EVALUATE
    DATESINPERIOD('Date'[Date]
                    ,StartDate
                    ,2
                    ,MONTH)

La consulta devuelve 61 filas que comienzan desde el máximo 05, 2025, hasta el 04 de julio de 2025:

Figura 3 – 2 meses de fechas generadas con fechas de I () (Figura del autor)

Puedo pasar el intervalo con un número arbitrario de días (por ejemplo, 14, 28, 30 o 31 días), y la función calcula automáticamente el rango de fechas.

Cuando paso números negativos, el rango de fechas va al pasado, comenzando con la fecha de inicio.

Usar fechasbetween ()

Ahora, veamos DATESBETWEEN().

DATESBETWEEN() Toma una fecha de inicio y final como parámetros.

Esto significa que debo calcular la fecha de finalización antes de usarla.

Cuando quiero obtener un rango de fecha del 05 de mayo al 29 de mayo de 2025, debo usar la siguiente consulta:

DEFINE
    VAR StartDate = "2025-05-05"
    
    VAR EndDate = "2025-05-25"
    
EVALUATE        
    DATESBETWEEN('Date'[Date]
                    ,StartDate
                    ,EndDate)

El resultado es el mismo que con DATESINPERIOD().

Sin embargo, hay un punto crucial: la fecha de finalización se incluye en el resultado.

Esto significa que puedo escribir algo como esto para obtener un rango de fechas durante dos meses del 05 de mayo al 05 de julio de 2025:

DEFINE
    VAR StartDate = "2025-05-05"
    
    VAR EndDate = "2025-07-05"
    
EVALUATE        
    DATESBETWEEN('Date'[Date]
                    ,StartDate
                    ,EndDate)

El resultado es muy similar al que usa DATESINPERIOD() y mes como intervalo, pero con una fila más:

Figura 4 – Resultado para un rango de fechas durante dos meses, más una fila (figura del autor)

Esto me da más flexibilidad para crear los rangos de fecha, ya que puedo precalcular la fecha de finalización de acuerdo con mis necesidades.

Uso en medidas: un ejemplo práctico.

Puedo usar estos métodos para calcular un total de funcionamiento en una medida.

Pero debemos tener cuidado de usar las dos funciones de la manera correcta

Por ejemplo, para calcular el total de funcionamiento por mes durante 25 días.

Mire el siguiente código, donde defino dos medidas usando las dos funciones:

DEFINE
    MEASURE 'All Measures'[25DayRollingTotal_A] =
        VAR DateRange =
            DATESINPERIOD('Date'[Date]
                            ,MIN ( 'Date'[Date] )
                            ,25
                            ,DAY)
        
        RETURN
            CALCULATE ( [Sum Online Sales]
                        , DateRange )

    MEASURE 'All Measures'[25DayRollingTotal_B] =
        VAR DateRange =
            DATESBETWEEN ( 'Date'[Date]
                            ,MIN ( 'Date'[Date] )
                            ,MIN ( 'Date'[Date] ) + 25 )
        
        RETURN
            CALCULATE ( [Sum Online Sales]
                        , DateRange )

EVALUATE
CALCULATETABLE (
    SUMMARIZECOLUMNS (
        'Date'[Year]
        ,'Date'[Month]
        ,"Sales", [Sum Online Sales]
        ,"25DayRollingTotal_A", [25DayRollingTotal_A]
        ,"25DayRollingTotal_B", [25DayRollingTotal_B]
        )
        ,'Date'[Date] >= DATE(2023, 01, 01) && 'Date'[Date] <= DATE(2023, 12, 31)
)
ORDER BY 'Date'[Month]

Este es el resultado:

Figura 5 – Resultado del total de ejecución durante 25 días con las dos funciones (figura del autor)

Observe la diferencia entre los dos resultados.

Esto es porque DATESBETWEEN() Incluye la fecha de finalización en el resultado, mientras DATESINPERIOD() Agrega el número de intervalos a la fecha de inicio, pero incluye la fecha de inicio.

Pruébelo con la siguiente consulta:

DEFINE
    VAR StartDate = DATE(2025,05,05)
    
    VAR EndDate = StartDate + 25
    
EVALUATE
    DATESINPERIOD('Date'[Date]
                    ,StartDate
                    ,25
                    ,DAY)
    
EVALUATE        
    DATESBETWEEN('Date'[Date]
                    ,StartDate
                    ,EndDate)

El primero devuelve 25 filas (05 de mayo – 29 de mayo de 2025) y el segundo devuelve 26 filas (05 de mayo – 30 de mayo de 2025).

Por lo tanto, debo cambiar una de las dos medidas para obtener el mismo resultado.

En este caso, la definición de cálculo es: comenzar desde la primera fecha y ir 25 en el futuro.

La lógica corregida es esta:

DEFINE
    MEASURE 'All Measures'[25DayRollingTotal_A] =
        VAR DateRange =
            DATESINPERIOD('Date'[Date]
                            ,MIN ( 'Date'[Date] )
                            ,25
                            ,DAY)
        
        RETURN
            CALCULATE ( [Sum Online Sales]
                        , DateRange )

    MEASURE 'All Measures'[25DayRollingTotal_B] =
        VAR DateRange =
            DATESBETWEEN ( 'Date'[Date]
                            ,MIN ( 'Date'[Date] )
                            ,MIN ( 'Date'[Date] ) + 24 )  // 24 instead of 25 days
        
        RETURN
            CALCULATE ( [Sum Online Sales]
                        , DateRange )

EVALUATE
CALCULATETABLE (
    SUMMARIZECOLUMNS (
        'Date'[Year]
        ,'Date'[Month]
        ,"Sales", [Sum Online Sales]
        ,"25DayRollingTotal_A", [25DayRollingTotal_A]
        ,"25DayRollingTotal_B", [25DayRollingTotal_B]
        )
        ,'Date'[Date] >= DATE(2023, 01, 01) && 'Date'[Date] <= DATE(2023, 12, 31)
)
ORDER BY 'Date'[Month]

Ahora, ambas medidas devuelven el mismo resultado:

Figura 6 – Resultado de las medidas corregidas (figura del autor)

Probé el rendimiento de ambas funciones para el mismo cálculo (total de rodillos durante 25 días), y los resultados fueron iguales. No hubo diferencia en el rendimiento o la eficiencia entre estos dos.

Incluso el plan de ejecución es el mismo.

Esto significa que DATEINPERIOD() es una función de acceso directo para DATESBETWEEN().

Conclusión

Desde el punto de vista de la funcionalidad, ambas funciones mostradas son casi equivalentes.

Lo mismo se aplica desde el punto de vista de rendimiento.

Difieren en la forma en que se define la fecha de finalización.

DATESINPERIOD() se basa en intervalos calendario, como días, meses, cuartos y años.
Esta función se usa cuando el rango de fechas debe calcularse en función del calendario.

Pero cuando tenemos una fecha de finalización predefinida o debemos calcular el rango de fecha entre dos fechas predefinidas, la DATESBETWEEN() la función es la función para usar.

Por ejemplo, uso DATESBETWEEN() Al realizar Inteligencia de tiempo cálculos durante semanas.

Puede leer esta pieza para obtener más información sobre los cálculos semanales:

Como puede leer, almaceno las fechas de inicio y finalización de la semana para cada fila en la tabla de datos.

De esta manera, puedo buscar fácilmente las fechas de inicio y finalización de cada fecha.

Entonces, cuando debemos seleccionar entre estas dos funciones, no es una cuestión de funcionalidad sino de requisitos definidos por las partes interesadas de los nuevos informes o el análisis de datos necesarios.

Lea este artículo para aprender a recopilar e interpretar datos de rendimiento con DAX Studio:

Como en mis artículos anteriores, uso el conjunto de datos de muestra Contoso. Puede descargar el conjunto de datos ContaSoretailDW gratis desde Microsoft aquí.

Los datos de Contoso se pueden usar libremente bajo la licencia MIT, como se describe En este documento. Cambié el conjunto de datos para cambiar los datos a fechas contemporáneas.