Inteligencia de Tiempo

TOTALYTD, SAMEPERIODLASTYEAR, DATESINPERIOD, PARALLELPERIOD y las 40 funciones para comparativas temporales — la categoría más poderosa de DAX

Intermedio Avanzado
🔍
⚠️

Antes de empezar: la tabla de calendario marcada

Este es el prerrequisito más importante de toda la inteligencia de tiempo. Sin él, nada funciona.

Para que las funciones de inteligencia de tiempo funcionen, NECESITAS obligatoriamente:

⚠️ Requisito 1: UNA TABLA DE CALENDARIO en tu modelo
  • Debe tener una columna de tipo fecha continua (sin huecos)
  • Debe cubrir todo el rango de fechas de tus datos
  • Debe tener UNA FILA por cada día
Calendario =
ADDCOLUMNS(
    CALENDARAUTO(),
    "Año", YEAR([Date]),
    "Mes", MONTH([Date]),
    "Trimestre", QUARTER([Date]),
    "Año-Mes", FORMAT([Date], "YYYY-MM")
)
⚠️ Requisito 2: MARCARLA COMO TABLA DE FECHAS en Power BI
  1. Seleccionar la tabla Calendario en el panel de campos
  2. Clic derecho → "Marcar como tabla de fechas"
  3. Seleccionar la columna de fecha como columna de fecha única
  4. ✅ Aparecerá un icono de calendario junto a la tabla
⚠️ Requisito 3: UNA RELACIÓN entre tu tabla de hechos y el Calendario
  • La columna de fecha de tus ventas → columna Date del Calendario
  • Relación de muchos a uno
  • Dirección de filtro: de Calendario hacia Ventas

¿Por qué es obligatorio?

Cuando Power BI ve que una tabla está marcada como tabla de fechas:

  • Desactiva la jerarquía de fechas automática
  • Permite que las funciones de Time Intelligence usen esa tabla correctamente
  • Garantiza que el contexto de filtro funcione bien con los períodos
// ❌ Esta medida puede dar resultados incorrectos o BLANK
Ventas YTD = TOTALYTD(SUM('Ventas'[Importe]), 'Ventas'[Fecha])
// Usas la columna de fecha directamente de la tabla de hechos

// ✅ Correcto:
Ventas YTD = TOTALYTD(SUM('Ventas'[Importe]), 'Calendario'[Date])
// Usas la tabla de calendario marcada
⚠️ Troubleshooting: Si tus medidas devuelven BLANK o resultados extraños
El 90% de las veces es porque:
  1. No tienes tabla de calendario marcada
  2. La relación entre Ventas y Calendario no existe o está inactiva
  3. El rango de fechas del calendario no cubre todas las fechas de los datos
Revisa estos tres puntos antes de buscar el bug en la fórmula DAX.
📊

Totales acumulados — Year-to-Date, Quarter-to-Date, Month-to-Date

YTD (Year-to-Date) significa "desde el inicio del año hasta hoy". QTD = desde el inicio del trimestre. MTD = desde el inicio del mes. Son las métricas más usadas en cualquier cuadro de mando: "¿Cómo vamos en lo que llevamos del año?"

TOTALYTD(<expresión>, <columna_fecha>, [fin_año])
Intermedio
Calcula la expresión acumulando desde el 1 de enero hasta la fecha máxima del contexto actual. El parámetro fin_año permite definir el fin del año fiscal (ej: "3/31" para año fiscal que termina en marzo).

Ejemplo básico:

// ✅ Ventas acumuladas en el año (desde 1 enero hasta la fecha del contexto)
Ventas YTD = TOTALYTD([Total Ventas], 'Calendario'[Date])
// En un visual de línea mes a mes:
// Enero: ventas de enero
// Febrero: ventas de enero + febrero
// Marzo: ventas de enero + febrero + marzo
// ... (siempre acumulando desde el 1 de enero)

Con año fiscal:

// ✅ Con año fiscal que termina el 31 de marzo
Ventas YTD Fiscal = TOTALYTD([Total Ventas], 'Calendario'[Date], "3/31")
// El "año" va del 1 de abril al 31 de marzo

Con filtro adicional:

// ✅ Con filtro adicional
Ventas YTD Electrónica =
TOTALYTD(
    [Total Ventas],
    'Calendario'[Date],
    'Productos'[Categoría] = "Electrónica"
)

// ✅ Equivalente usando DATESYTD (más flexible)
Ventas YTD v2 = CALCULATE([Total Ventas], DATESYTD('Calendario'[Date]))
DATESYTD / DATESQTD / DATESMTD(<columna_fecha>, [fin_año])
Intermedio
Devuelven una TABLA con las fechas desde el inicio del año/trimestre/mes hasta la fecha máxima del contexto. Se usan dentro de CALCULATE para máxima flexibilidad.

Diferencia entre TOTAL... y DATES...:

// TOTALYTD es un atajo para:
CALCULATE([Total Ventas], DATESYTD('Calendario'[Date]))
// Ambas dan el mismo resultado — elige la que prefieras leer

// ✅ La ventaja de DATES... es que puedes combinarlo con otras cosas
Margen YTD = CALCULATE([Total Margen], DATESYTD('Calendario'[Date]))
Nº Clientes YTD = CALCULATE([Clientes Únicos], DATESYTD('Calendario'[Date]))
// Reutilizas el mismo patrón para cualquier medida
TOTALQTD / TOTALMTD(<expresión>, <columna_fecha>)
Intermedio
Como TOTALYTD pero acumulan desde el inicio del trimestre o del mes respectivamente.
// ✅ ¿Cómo vamos en lo que llevamos del trimestre?
Ventas QTD = TOTALQTD([Total Ventas], 'Calendario'[Date])

// ✅ ¿Cómo vamos en lo que llevamos del mes?
Ventas MTD = TOTALMTD([Total Ventas], 'Calendario'[Date])

// Tabla resumen de todos los acumulados:
// Medida       | Ene | Feb | Mar | Q1 Total | Año Total
// Ventas MTD   | 10K | 12K |  8K |          |
// Ventas QTD   | 10K | 22K | 30K | 30K      |
// Ventas YTD   | 10K | 22K | 30K | 30K      | (en Q1 es lo mismo que QTD)
🔙

Comparar con el mismo período del año / trimestre / mes anterior

SAMEPERIODLASTYEAR(<columna_fecha>)
Intermedio
Devuelve una tabla con las mismas fechas que el contexto actual pero del año anterior. Es la función más usada para comparativas YoY (Year-over-Year).

Ejemplos básicos:

// ✅ Ventas del mismo período del año anterior
Ventas Año Anterior = CALCULATE([Total Ventas], SAMEPERIODLASTYEAR('Calendario'[Date]))

// ✅ Variación absoluta vs año anterior
Variación YoY = [Total Ventas] - [Ventas Año Anterior]

// ✅ Variación porcentual vs año anterior
Variación YoY % = DIVIDE([Total Ventas] - [Ventas Año Anterior], [Ventas Año Anterior])

KPI completo con formato:

// ✅ Con formato bonito para mostrar
KPI YoY =
VAR Actual = [Total Ventas]
VAR Anterior = [Ventas Año Anterior]
VAR Var = DIVIDE(Actual - Anterior, Anterior)
RETURN
    FORMAT(Actual, "#,##0 €") & " (" & FORMAT(Var, "+0.0%;-0.0%") & " vs año ant.)"

// ✅ Funciona también con YTD — comparativa YTD vs YTD año anterior
Ventas YTD Año Anterior =
CALCULATE(
    [Total Ventas],
    SAMEPERIODLASTYEAR(DATESYTD('Calendario'[Date]))
)
PREVIOUSMONTH / PREVIOUSQUARTER / PREVIOUSYEAR(<columna_fecha>)
Intermedio
Devuelven las fechas del mes/trimestre/año anterior completo al contexto actual. A diferencia de SAMEPERIODLASTYEAR, estas funciones devuelven el período INMEDIATAMENTE anterior.

Diferencia clave SAMEPERIODLASTYEAR vs PREVIOUSYEAR:

// Si el contexto es Q1 2024 (enero, febrero, marzo):
SAMEPERIODLASTYEAR → Q1 2023 (mismo trimestre, año anterior)
PREVIOUSYEAR       → todo 2023 (el año anterior completo)

// Si el contexto es marzo 2024:
PREVIOUSMONTH      → febrero 2024 (el mes anterior completo)
SAMEPERIODLASTYEAR → marzo 2023 (el mismo mes, año anterior)

Ejemplos prácticos:

// ✅ Ventas del mes anterior (para comparativa MoM)
Ventas Mes Anterior = CALCULATE([Total Ventas], PREVIOUSMONTH('Calendario'[Date]))

// ✅ Variación MoM (Month-over-Month)
Variación MoM = [Total Ventas] - [Ventas Mes Anterior]
Variación MoM % = DIVIDE([Total Ventas] - [Ventas Mes Anterior], [Ventas Mes Anterior])

// ✅ Ventas del trimestre anterior
Ventas Q Anterior = CALCULATE([Total Ventas], PREVIOUSQUARTER('Calendario'[Date]))

// ✅ Ventas del año anterior completo
Ventas Año Anterior Completo = CALCULATE([Total Ventas], PREVIOUSYEAR('Calendario'[Date]))
🔜

Mirar al futuro: NEXT...

NEXTMONTH / NEXTQUARTER / NEXTYEAR(<columna_fecha>)
Intermedio
Como las funciones PREVIOUS pero hacia adelante en el tiempo. Útiles para mostrar proyecciones, presupuestos futuros y comparativas con datos de períodos próximos.
// ✅ ¿Cuál es el presupuesto del mes que viene?
Presupuesto Mes Siguiente = CALCULATE(SUM('Presupuesto'[Importe]), NEXTMONTH('Calendario'[Date]))

// ✅ Diferencia entre lo que llevamos del año y lo que viene el año próximo
Gap vs Próximo Año = [Total Ventas] - CALCULATE([Total Ventas], NEXTYEAR('Calendario'[Date]))
💡 Cuándo usar NEXT...
Las funciones NEXT... tienen sentido principalmente cuando tu tabla de datos incluye datos futuros (presupuestos, forecasts). Si solo tienes datos históricos, NEXT... devolverá BLANK porque no hay datos en el futuro.
↔️

DATEADD y PARALLELPERIOD — mover el tiempo con precisión

DATEADD(<columna_fecha>, <numero_intervalos>, <intervalo>)
Intermedio — Avanzado
Desplaza las fechas del contexto actual en N intervalos (DAY, MONTH, QUARTER, YEAR). Positivo = hacia el futuro, negativo = hacia el pasado. Es la función más flexible para desplazamientos temporales.
// ✅ Las mismas fechas de hace 1 año (equivalente a SAMEPERIODLASTYEAR)
DATEADD('Calendario'[Date], -1, YEAR)

// ✅ Las mismas fechas de hace 3 meses
DATEADD('Calendario'[Date], -3, MONTH)

// ✅ El mismo día de la semana anterior
DATEADD('Calendario'[Date], -7, DAY)

// ✅ Ventas hace 2 trimestres
Ventas Hace 2Q = CALCULATE([Total Ventas], DATEADD('Calendario'[Date], -2, QUARTER))

// ✅ Comparativa con hace N períodos (dinámico con slicer)
Ventas Período Anterior =
VAR N = SELECTEDVALUE('Selector Períodos'[Valor], 1)
RETURN
    CALCULATE([Total Ventas], DATEADD('Calendario'[Date], -N, MONTH))
PARALLELPERIOD(<columna_fecha>, <numero_intervalos>, <intervalo>)
Avanzado
Similar a DATEADD pero devuelve el período COMPLETO desplazado, no solo las fechas equivalentes. La diferencia es sutil pero importante.

Diferencia DATEADD vs PARALLELPERIOD:

// Si el contexto es del 1 al 15 de marzo (media quincena):

DATEADD('Calendario'[Date], -1, MONTH)
→ del 1 al 15 de FEBRERO (mismas fechas, mes anterior)

PARALLELPERIOD('Calendario'[Date], -1, MONTH)
→ TODO FEBRERO (el mes completo anterior)

// Cuándo usar cada una:
// DATEADD: cuando quieres comparar exactamente el mismo período
// PARALLELPERIOD: cuando quieres el período completo
//   (ej: comparar con el mes anterior completo aunque el mes actual esté a medias)
💡 Uso práctico
En un gráfico de líneas mes a mes, si el mes actual solo tiene 15 días:
DATEADD → compara esos 15 días con los primeros 15 del mes anterior (justo)
PARALLELPERIOD → compara esos 15 días con el mes anterior completo (puede ser engañoso)

Para cuadros de mando ejecutivos donde no quieres medias partidas, usa PARALLELPERIOD.
Para análisis precisos día a día, usa DATEADD.
DATESBETWEEN / DATESINPERIOD
Intermedio — Avanzado
DATESBETWEEN: Devuelve las fechas entre dos fechas específicas (ambas inclusive).
DATESINPERIOD: Devuelve fechas para un período de N intervalos a partir de una fecha de inicio. Perfecta para ventanas móviles (rolling windows).
// ✅ DATESBETWEEN — Ventas en un rango de fechas específico
Ventas Q1 2024 =
CALCULATE(
    [Total Ventas],
    DATESBETWEEN('Calendario'[Date], DATE(2024,1,1), DATE(2024,3,31))
)

// ✅ Ventas en los últimos 30 días exactos
Ventas Últimos 30d =
CALCULATE(
    [Total Ventas],
    DATESBETWEEN('Calendario'[Date], TODAY() - 30, TODAY())
)

// ✅ DATESINPERIOD — Últimos 12 meses desde la fecha máxima del contexto
Ventas Últimos 12M =
CALCULATE(
    [Total Ventas],
    DATESINPERIOD('Calendario'[Date], MAX('Calendario'[Date]), -12, MONTH)
)

// ✅ Media móvil de 3 meses (rolling average)
Media Móvil 3M =
CALCULATE(
    AVERAGE('Ventas'[Importe]),
    DATESINPERIOD('Calendario'[Date], MAX('Calendario'[Date]), -3, MONTH)
)
💰

Saldos de apertura y cierre — para contabilidad y stock

Estas funciones son esenciales para análisis financieros y de inventario donde necesitas saber el valor al INICIO o al FINAL de un período, no el total acumulado. Piensa en el saldo de una cuenta bancaria: no quieres la suma de todos los movimientos, quieres el saldo al principio y al final del mes.

OPENINGBALANCE... / CLOSINGBALANCE...
Avanzado
OPENINGBALANCE...: evalúa la expresión en el último día del período ANTERIOR (= el saldo de apertura del período actual)
CLOSINGBALANCE...: evalúa la expresión en el último día del período ACTUAL (= el saldo de cierre)
Variantes: MONTH, QUARTER, YEAR
// ✅ Stock al inicio del mes (lo que había el último día del mes anterior)
Stock Apertura Mes =
OPENINGBALANCEMONTH(
    LASTNONBLANK('Inventario'[Fecha], SUM('Inventario'[Stock])),
    'Calendario'[Date]
)

// ✅ Stock al cierre del mes
Stock Cierre Mes =
CLOSINGBALANCEMONTH(
    SUM('Inventario'[Stock]),
    'Calendario'[Date]
)

// ✅ Saldo bancario al cierre del trimestre
Saldo Cierre Q =
CLOSINGBALANCEQUARTER(
    SUM('Cuentas'[Saldo]),
    'Calendario'[Date]
)

// ✅ Saldo al cierre del año fiscal (que termina en marzo)
Saldo Cierre Año Fiscal =
CLOSINGBALANCEYEAR(
    SUM('Cuentas'[Saldo]),
    'Calendario'[Date],
    "3/31"
)
💡 CLOSINGBALANCE vs MAX de fecha
La diferencia entre CLOSINGBALANCE y un simple MAX de fecha es que CLOSING... entiende el concepto de "período". Si el contexto es el trimestre Q1, CLOSINGBALANCEMONTH en marzo da el saldo del 31 de marzo, no el máximo global de todo el modelo.
📌

FIRSTDATE, LASTDATE y variantes — encontrar fechas clave

Tabla comparativa

Función Qué devuelve Usa contexto
FIRSTDATE Tabla con la primera fecha del contexto
LASTDATE Tabla con la última fecha del contexto
FIRSTNONBLANK Primera fecha donde la expresión no es BLANK
LASTNONBLANK Última fecha donde la expresión no es BLANK
FIRSTNONBLANKVALUE Valor de la expresión en la primera fecha no BLANK
LASTNONBLANKVALUE Valor de la expresión en la última fecha no BLANK
FIRSTDATE / LASTDATE(<columna_fecha>)
Intermedio
Devuelven UNA TABLA con la primera o última fecha del contexto actual. Se usan principalmente dentro de CALCULATE.
// ✅ Saldo al último día del período visible
Saldo Última Fecha = CALCULATE(SUM('Cuentas'[Saldo]), LASTDATE('Calendario'[Date]))

// ✅ Valor al primer día del año actual
Stock Inicio Año = CALCULATE(SUM('Inventario'[Stock]), FIRSTDATE(DATESYTD('Calendario'[Date])))
LASTNONBLANK / LASTNONBLANKVALUE
Avanzado
Primera/última fecha donde la expresión devuelve algo distinto de BLANK. Útiles cuando no todos los días tienen datos y necesitas encontrar el primer/último día con dato real.
// ✅ Última fecha con ventas registradas (no el último día del calendario)
Última Fecha con Ventas = LASTNONBLANK('Calendario'[Date], CALCULATE(COUNTROWS('Ventas')))

// ✅ Último precio registrado de un producto
Último Precio = LASTNONBLANKVALUE('Calendario'[Date], MAX('Precios'[Precio]))

// ✅ Stock actual (el de la fecha más reciente con datos)
Stock Actual = LASTNONBLANKVALUE('Calendario'[Date], SUM('Inventario'[Stock]))
🌐

Todos los períodos

ALL con fechas
Intermedio
A veces necesitas ignorar todos los filtros de fecha para mostrar el total general. El patrón correcto es combinar CALCULATE con ALL sobre el calendario.
// ✅ Total de todos los años (sin filtro de fecha)
Total Histórico = CALCULATE([Total Ventas], ALL('Calendario'))

// ✅ Porcentaje sobre el total histórico
% del Total Histórico = DIVIDE([Total Ventas], CALCULATE([Total Ventas], ALL('Calendario')))

// ✅ Total del año completo (aunque el contexto sea un solo mes)
Total Año Completo =
CALCULATE(
    [Total Ventas],
    DATESYTD(LASTDATE('Calendario'[Date]))
)
📅

Funciones de semana (WEEK)

Las funciones de semana permiten comparar datos con la semana anterior, la siguiente, o acumular desde el inicio de la semana actual. Menos usadas que mes y año, pero muy útiles en análisis operativos y logísticos donde la semana es la unidad natural de planificación.

⚠️ Ojo con esto: estas funciones necesitan que tu tabla Calendario tenga una columna de fecha contigua y sin huecos, y que esté marcada como tabla de fechas en Power BI. Sin eso, los resultados pueden ser incorrectos o dar error.
PREVIOUSWEEK(<columna_fechas>)
Intermedio
Devuelve una tabla con todas las fechas de la semana anterior a la semana visible en el contexto de filtro actual. Equivalente a PREVIOUSMONTH pero para semanas. La semana empieza en domingo por defecto (el comportamiento ISO puede variar según la configuración regional del modelo).

Ventas de la semana anterior:

// Ventas de la semana anterior:
Ventas Semana Anterior =
CALCULATE(
    [Total Ventas],
    PREVIOUSWEEK('Calendario'[Fecha])
)

Diferencia semana actual vs anterior:

Diferencia Semanal =
VAR SemanaActual = [Total Ventas]
VAR SemanaAnt    = CALCULATE([Total Ventas], PREVIOUSWEEK('Calendario'[Fecha]))
RETURN
    IF(
        ISBLANK(SemanaAnt),
        BLANK(),
        SemanaActual - SemanaAnt
    )
💡 PREVIOUSWEEK en operaciones: es especialmente útil en dashboards de operaciones y logística donde el equipo analiza rendimiento semana a semana. Combínala con un visual de línea para ver la evolución semanal de forma inmediata.
NEXTWEEK(<columna_fechas>)
Intermedio
Devuelve una tabla con todas las fechas de la semana siguiente a la semana visible en el contexto actual. Útil para proyecciones a corto plazo o para comparar pedidos ya registrados para la próxima semana.

Pedidos registrados para la próxima semana:

// Pedidos registrados para la próxima semana:
Pedidos Próxima Semana =
CALCULATE(
    COUNTROWS(Pedidos),
    NEXTWEEK('Calendario'[Fecha])
)

% de variación previsto semana siguiente:

Crecimiento Previsto Semanal =
VAR VentasActual    = [Total Ventas]
VAR VentasSiguiente = CALCULATE([Total Ventas], NEXTWEEK('Calendario'[Fecha]))
RETURN
    DIVIDE(VentasSiguiente - VentasActual, VentasActual)
TOTALWTD(<expresión>, <columna_fechas> [, <filtro>] [, <fin_semana>])
Intermedio
Calcula el total acumulado desde el inicio de la semana hasta la fecha visible en el contexto (Week-To-Date). Es el equivalente semanal de TOTALYTD y TOTALMTD. El parámetro opcional fin_semana indica qué día es el último de la semana ("0" = sábado, "1" = domingo…).

Ventas acumuladas desde el inicio de la semana:

// Ventas acumuladas desde el inicio de la semana actual:
Ventas WTD =
TOTALWTD(
    [Total Ventas],
    'Calendario'[Fecha]
)

// WTD con semana que termina el domingo (lunes a domingo):
Ventas WTD (Lun-Dom) =
TOTALWTD(
    [Total Ventas],
    'Calendario'[Fecha],
    "0"
)

Variación WTD vs WTD semana anterior:

WTD vs WTD Anterior =
VAR WTD_Actual   = [Ventas WTD]
VAR WTD_Anterior = CALCULATE([Ventas WTD], PREVIOUSWEEK('Calendario'[Fecha]))
RETURN DIVIDE(WTD_Actual - WTD_Anterior, WTD_Anterior)
💡 El parámetro fin_semana de TOTALWTD puede ser confuso. Prueba tu medida con datos conocidos antes de publicar — el día de inicio de semana varía según el país y la configuración regional del modelo. "0" = semana termina el sábado, "1" = termina el domingo.
🚩

STARTOF — Primer día del período

Las funciones STARTOF devuelven el primer día del período que contiene la fecha del contexto actual. Devuelven un valor escalar de tipo fecha (no una tabla), lo que las hace perfectas dentro de cálculos, columnas calculadas o como argumento de otras funciones DAX.

💡 STARTOF vs FIRSTDATE: a diferencia de FIRSTDATE (que devuelve la primera fecha con datos en el contexto), STARTOF devuelve siempre el primer día del período natural, aunque no haya datos ese día. Son sutilmente diferentes y cada una tiene su momento.
STARTOFWEEK(<columna_fechas> [, <fin_semana>])
Intermedio
Devuelve el primer día de la semana que contiene la fecha del contexto actual. Por defecto la semana empieza el domingo. El parámetro opcional fin_semana permite ajustar qué día es el último (y por tanto cuál es el primero).

Primer día de la semana y usos habituales:

// Primer día de la semana actual (valor escalar):
Inicio Semana Actual =
STARTOFWEEK('Calendario'[Fecha])

// Columna calculada en la tabla Calendario
// (útil para agrupar días por semana en visuales):
'Calendario'[Inicio de Semana] =
STARTOFWEEK('Calendario'[Fecha])

// Ventas desde el inicio de la semana (WTD manual con control total):
Ventas Desde Inicio Semana =
CALCULATE(
    [Total Ventas],
    DATESBETWEEN(
        'Calendario'[Fecha],
        STARTOFWEEK('Calendario'[Fecha]),
        LASTDATE('Calendario'[Fecha])
    )
)
STARTOFMONTH(<columna_fechas>)
Principiante / Intermedio
Devuelve el primer día del mes que contiene la fecha del contexto actual. Muy usada para calcular rangos de fechas dinámicos, comparar desde inicio de mes o construir períodos personalizados con DATESBETWEEN.
// Primer día del mes actual:
Inicio Mes Actual =
STARTOFMONTH('Calendario'[Fecha])

// MTD manual con control total del rango:
Ventas MTD Manual =
CALCULATE(
    [Total Ventas],
    DATESBETWEEN(
        'Calendario'[Fecha],
        STARTOFMONTH(LASTDATE('Calendario'[Fecha])),
        LASTDATE('Calendario'[Fecha])
    )
)

// Días transcurridos desde inicio de mes:
Días Transcurridos Mes =
DATEDIFF(
    STARTOFMONTH(TODAY()),
    TODAY(),
    DAY
) + 1
📌 Usa STARTOFMONTH con DATESBETWEEN cuando necesites un MTD con lógica personalizada, como excluir fines de semana o aplicar calendarios de negocio propios. Te da control total sobre el rango, a diferencia de TOTALMTD.
STARTOFQUARTER(<columna_fechas>)
Intermedio
Devuelve el primer día del trimestre que contiene la fecha del contexto actual. Por ejemplo, si estás en mayo (Q2), devuelve el 1 de abril.
// Primer día del trimestre actual:
Inicio Trimestre Actual =
STARTOFQUARTER('Calendario'[Fecha])

// QTD manual:
Ventas QTD Manual =
CALCULATE(
    [Total Ventas],
    DATESBETWEEN(
        'Calendario'[Fecha],
        STARTOFQUARTER(LASTDATE('Calendario'[Fecha])),
        LASTDATE('Calendario'[Fecha])
    )
)

// Comparar trimestre actual vs mismo período año anterior:
Ventas Mismo Período Q Año Anterior =
VAR InicioQ    = STARTOFQUARTER(LASTDATE('Calendario'[Fecha]))
VAR InicioQAnt = DATE(YEAR(InicioQ) - 1, MONTH(InicioQ), DAY(InicioQ))
VAR FinQAnt    = LASTDATE(SAMEPERIODLASTYEAR('Calendario'[Fecha]))
RETURN
    CALCULATE(
        [Total Ventas],
        DATESBETWEEN('Calendario'[Fecha], InicioQAnt, FinQAnt)
    )
STARTOFYEAR(<columna_fechas> [, <fin_año>])
Principiante / Intermedio
Devuelve el primer día del año natural o fiscal que contiene la fecha del contexto. El parámetro opcional fin_año define el último día del año fiscal (por ejemplo "06-30" si tu año fiscal termina el 30 de junio). Sin parámetro, usa el año natural (1 de enero).

Año natural y YTD manual:

// Primer día del año natural:
Inicio Año Actual =
STARTOFYEAR('Calendario'[Fecha])
// → devuelve 01/01/[año actual]

// YTD manual con control total:
Ventas YTD Manual =
CALCULATE(
    [Total Ventas],
    DATESBETWEEN(
        'Calendario'[Fecha],
        STARTOFYEAR(LASTDATE('Calendario'[Fecha])),
        LASTDATE('Calendario'[Fecha])
    )
)

Con año fiscal y días transcurridos:

// Con año fiscal que termina el 30 de junio:
Inicio Año Fiscal =
STARTOFYEAR('Calendario'[Fecha], "06-30")
// Si estás en noviembre 2024 → devuelve 01/07/2024

// Días del año transcurridos:
Días del Año Transcurridos =
DATEDIFF(
    STARTOFYEAR(TODAY()),
    TODAY(),
    DAY
) + 1
💡 El parámetro fin_año indica el ÚLTIMO día del año fiscal, no el primero. Si tu año fiscal empieza el 1 de julio, escribe "06-30" (30 de junio). ¡Es contra-intuitivo pero es así! Siempre verifica con una fecha conocida antes de publicar.
🏆

Los 10 patrones de Time Intelligence que usarás en casi todos los proyectos

🏆 Patrón 1: YoY (Year-over-Year) completo
Ventas YoY =
VAR Actual = [Total Ventas]
VAR Anterior = CALCULATE([Total Ventas], SAMEPERIODLASTYEAR('Calendario'[Date]))
VAR Variacion = DIVIDE(Actual - Anterior, Anterior)
RETURN
    IF(
        NOT ISBLANK(Anterior),
        FORMAT(Actual, "#,##0 €") & " (" & FORMAT(Variacion, "+0.0%;-0.0%") & " vs AA)",
        FORMAT(Actual, "#,##0 €") & " (sin dato año anterior)"
    )
🏆 Patrón 2: YTD vs YTD año anterior
Ventas YTD = TOTALYTD([Total Ventas], 'Calendario'[Date])
Ventas YTD AA = CALCULATE([Ventas YTD], SAMEPERIODLASTYEAR('Calendario'[Date]))
Crecimiento YTD = DIVIDE([Ventas YTD] - [Ventas YTD AA], [Ventas YTD AA])
🏆 Patrón 3: Media móvil N meses (rolling average)
Media Móvil 3M =
CALCULATE(
    AVERAGEX(
        VALUES('Calendario'[Año-Mes]),
        CALCULATE([Total Ventas])
    ),
    DATESINPERIOD('Calendario'[Date], LASTDATE('Calendario'[Date]), -3, MONTH)
)
🏆 Patrón 4: Comparativa MoM (Month-over-Month)
Ventas MoM =
VAR Actual = [Total Ventas]
VAR MesAnterior = CALCULATE([Total Ventas], PREVIOUSMONTH('Calendario'[Date]))
RETURN
    DIVIDE(Actual - MesAnterior, MesAnterior)
🏆 Patrón 5: Mejor período histórico
Record Histórico =
CALCULATE(
    MAXX(VALUES('Calendario'[Año-Mes]), CALCULATE([Total Ventas])),
    ALL('Calendario')
)

Es Record = IF([Total Ventas] >= [Record Histórico], "🏆 RÉCORD", "")
🏆 Patrón 6: Acumulado hasta hoy (YTD dinámico)
Ventas YTD Hasta Hoy =
CALCULATE(
    [Total Ventas],
    DATESYTD('Calendario'[Date]),
    'Calendario'[Date] <= TODAY()
)
🏆 Patrón 7: Semáforo de cumplimiento YTD
Semáforo YTD =
VAR CumplimientoYTD = DIVIDE([Ventas YTD], [Presupuesto YTD])
RETURN
    SWITCH(
        TRUE(),
        CumplimientoYTD >= 1.00, "🟢 En objetivo",
        CumplimientoYTD >= 0.90, "🟡 Cerca del objetivo",
        "🔴 Por debajo del objetivo"
    )
🏆 Patrón 8: Días transcurridos y restantes del año
Días Transcurridos = DATEDIFF(DATE(YEAR(TODAY()), 1, 1), TODAY(), DAY)
Días Restantes Año = DATEDIFF(TODAY(), DATE(YEAR(TODAY()), 12, 31), DAY)
% Año Transcurrido = DIVIDE([Días Transcurridos], 365)
🏆 Patrón 9: Forecast simple (extrapolación lineal)
Forecast Mes =
VAR TasaCrecimiento = DIVIDE([Ventas YoY], CALCULATE([Total Ventas], PREVIOUSYEAR('Calendario'[Date])))
VAR BaseAnoAnterior = CALCULATE([Total Ventas], SAMEPERIODLASTYEAR('Calendario'[Date]))
RETURN
    IF(ISBLANK([Total Ventas]), BaseAnoAnterior * (1 + TasaCrecimiento), [Total Ventas])
🏆 Patrón 10: Rolling 12 meses
Rolling 12M =
CALCULATE(
    [Total Ventas],
    DATESINPERIOD('Calendario'[Date], LASTDATE('Calendario'[Date]), -12, MONTH)
)
🚀 Siguiente paso
¡La inteligencia de tiempo ya es tuya! Con estos 10 patrones puedes construir prácticamente cualquier análisis temporal que un cuadro de mando ejecutivo pueda necesitar. Ahora vamos con las funciones de Relaciones — menos glamurosas pero absolutamente fundamentales para modelos de datos avanzados.