{"componentChunkName":"component---src-templates-blog-post-js","path":"/blog/power-bi-dax-time-intelligence-tabela-calendario/","result":{"data":{"markdownRemark":{"frontmatter":{"title":"Power BI: DAX time intelligence sem tabela calendário quebrar","description":"Funcoes de time intelligence do DAX so funcionam com uma tabela de datas bem construida. Veja como montar o calendario, marca-lo como date table e evitar erros comuns.","date":"29 de setembro de 2026","thumbnail":null},"html":"<p>Quase todo relatorio corporativo precisa de comparativos temporais: acumulado do ano, variacao contra o mesmo periodo do ano anterior, media movel de 3 meses. O DAX oferece um arsenal de funcoes de time intelligence justamente para isso — mas elas dependem de uma premissa que muita gente ignora e que e a causa da maioria dos numeros errados em producao: <strong>uma tabela de datas dedicada, continua e marcada como tal</strong>. Sem ela, <code>TOTALYTD</code>, <code>SAMEPERIODLASTYEAR</code> e afins retornam valores silenciosamente errados ou simplesmente em branco.</p>\n<p><strong>Por que a coluna de data da tabela fato nao basta</strong></p>\n<p>O erro classico e aplicar time intelligence direto sobre a coluna <code>DataVenda</code> da tabela de fato. As funcoes de time intelligence do DAX assumem internamente que existe uma tabela de datas com uma linha por dia, sem buracos, cobrindo todo o intervalo do modelo. Elas usam essa continuidade para deslocar contextos de filtro (\"mesmo periodo, ano anterior\") de forma confiavel.</p>\n<p>Se voce usa a coluna da fato:</p>\n<ul>\n<li>Dias sem transacao nao existem na coluna, entao a serie tem buracos e o deslocamento de periodo fica impreciso.</li>\n<li>Funcoes como <code>DATESYTD</code> podem funcionar por sorte em alguns cenarios e falhar em outros, o que e pior do que falhar sempre — o bug passa desapercebido.</li>\n<li>Voce nao consegue relacionar multiplas fatos (vendas, metas, estoque) a um unico eixo temporal comum.</li>\n</ul>\n<p><strong>Como construir a tabela calendario</strong></p>\n<p>A forma mais limpa e uma tabela calculada com <code>CALENDAR</code> ou <code>CALENDARAUTO</code>, garantindo continuidade dia a dia entre o menor e o maior valor do modelo:</p>\n<pre><code>Dim Calendario =\nADDCOLUMNS (\n    CALENDAR ( DATE ( 2020, 1, 1 ), DATE ( 2027, 12, 31 ) ),\n    \"Ano\", YEAR ( [Date] ),\n    \"MesNum\", MONTH ( [Date] ),\n    \"MesNome\", FORMAT ( [Date], \"MMM\" ),\n    \"AnoMes\", FORMAT ( [Date], \"YYYY-MM\" ),\n    \"Trimestre\", \"T\" &#x26; FORMAT ( [Date], \"Q\" )\n)\n</code></pre>\n<p>Defina o intervalo com folga em relacao aos seus dados — nunca deixe a tabela terminar no meio de um ano fiscal, senao os acumulados do ultimo periodo ficam truncados. Em modelos grandes, prefira construir o calendario no Power Query ou na fonte, para nao pagar o custo de uma coluna calculada em cada refresh, mas o principio e o mesmo.</p>\n<p><strong>O passo que quase todo mundo pula: Mark as Date Table</strong></p>\n<p>Criar a tabela e relacionar com a fato nao e suficiente. Voce precisa marcar a tabela como tabela de datas (<code>Mark as date table</code>, apontando a coluna de data). Isso faz duas coisas essenciais:</p>\n<ol>\n<li>Informa ao engine qual coluna representa a continuidade temporal, permitindo que as funcoes de time intelligence funcionem de forma deterministica.</li>\n<li>Remove as hierarquias automaticas de data (Auto Date/Time) associadas as colunas da fato, que inflam o modelo com tabelas ocultas por coluna de data.</li>\n</ol>\n<p>Sem esse passo, o comportamento de funcoes como <code>SAMEPERIODLASTYEAR</code> fica dependente de heuristicas internas e pode divergir entre visuais. Marcar a tabela e a diferenca entre time intelligence confiavel e um jogo de adivinhacao.</p>\n<p><strong>Padroes de medidas que voce vai reusar</strong></p>\n<p>Com a tabela pronta e marcada, as medidas ficam limpas e componiveis:</p>\n<pre><code>Vendas YTD = TOTALYTD ( [Total Vendas], 'Dim Calendario'[Date] )\n\nVendas Ano Anterior =\nCALCULATE ( [Total Vendas], SAMEPERIODLASTYEAR ( 'Dim Calendario'[Date] ) )\n\nVar % YoY =\nDIVIDE ( [Total Vendas] - [Vendas Ano Anterior], [Vendas Ano Anterior] )\n\nMedia Movel 3M =\nAVERAGEX (\n    DATESINPERIOD ( 'Dim Calendario'[Date], MAX ( 'Dim Calendario'[Date] ), -3, MONTH ),\n    [Total Vendas]\n)\n</code></pre>\n<p>Repare que todas apontam para a coluna de data do calendario, nunca para a fato. Esse e o contrato que mantem tudo coerente.</p>\n<p><strong>Armadilhas de producao</strong></p>\n<ul>\n<li><strong>Ano fiscal diferente do calendario:</strong> se sua empresa fecha o ano em julho, use o parametro de fim de ano fiscal em <code>TOTALYTD ( ..., \"06-30\" )</code> ou construa colunas fiscais proprias. Ignorar isso gera acumulados errados nos relatorios da diretoria.</li>\n<li><strong>Auto Date/Time ainda ligado:</strong> verifique nas opcoes do arquivo e desligue globalmente. Deixar ligado junto com o calendario duplica o custo em memoria e confunde quem edita o modelo.</li>\n<li><strong>Relacionamento inativo ou multiplas datas:</strong> modelos com varias datas relevantes (data do pedido, data de entrega) exigem role-playing dimensions com <code>USERELATIONSHIP</code> — nao tente resolver com duas tabelas calendario sem necessidade.</li>\n<li><strong>Filtro por coluna de texto AnoMes:</strong> ordenar <code>AnoMes</code> alfabeticamente funciona porque usamos formato <code>YYYY-MM</code>; se usar <code>MMM/YYYY</code>, configure <code>Sort by column</code> com uma coluna numerica, senao os meses saem fora de ordem.</li>\n</ul>\n<p><strong>Fechamento</strong></p>\n<p>Time intelligence no DAX e poderoso, mas e tao confiavel quanto a tabela de datas por baixo dele. Uma dimensao calendario continua, com intervalo folgado, marcada como date table e com Auto Date/Time desligado, elimina de uma vez a maior fonte de numeros errados em relatorios corporativos. Se sua empresa esta escalando modelos Power BI e precisa de governanca de dados que sustente decisoes de diretoria, a Dynamic Solucoes ajuda a estruturar modelagem, DAX e ALM da sua camada analitica com seguranca.</p>\n<p>Almost every corporate report needs time-based comparisons: year-to-date totals, variance against the same period last year, 3-month moving averages. DAX offers a full arsenal of time intelligence functions precisely for this — but they rely on an assumption many people ignore, and that is the root cause of most wrong numbers in production: <strong>a dedicated, continuous date table, properly marked as such</strong>. Without it, <code>TOTALYTD</code>, <code>SAMEPERIODLASTYEAR</code> and their siblings return silently wrong values or simply blanks.</p>\n<p><strong>Why the fact table's date column isn't enough</strong></p>\n<p>The classic mistake is applying time intelligence directly on the <code>SalesDate</code> column of the fact table. DAX time intelligence functions internally assume a date table with one row per day, no gaps, covering the model's full range. They use that continuity to shift filter contexts (\"same period, prior year\") reliably.</p>\n<p>If you use the fact column:</p>\n<ul>\n<li>Days with no transactions don't exist in the column, so the series has gaps and period shifting becomes imprecise.</li>\n<li>Functions like <code>DATESYTD</code> may work by luck in some scenarios and fail in others, which is worse than always failing — the bug goes unnoticed.</li>\n<li>You can't relate multiple fact tables (sales, targets, inventory) to a single shared time axis.</li>\n</ul>\n<p><strong>How to build the calendar table</strong></p>\n<p>The cleanest approach is a calculated table with <code>CALENDAR</code> or <code>CALENDARAUTO</code>, guaranteeing day-by-day continuity between the model's minimum and maximum values:</p>\n<pre><code>Dim Calendar =\nADDCOLUMNS (\n    CALENDAR ( DATE ( 2020, 1, 1 ), DATE ( 2027, 12, 31 ) ),\n    \"Year\", YEAR ( [Date] ),\n    \"MonthNum\", MONTH ( [Date] ),\n    \"MonthName\", FORMAT ( [Date], \"MMM\" ),\n    \"YearMonth\", FORMAT ( [Date], \"YYYY-MM\" ),\n    \"Quarter\", \"Q\" &#x26; FORMAT ( [Date], \"Q\" )\n)\n</code></pre>\n<p>Set the range with margin around your data — never let the table end in the middle of a fiscal year, or the last period's totals get truncated. In large models, prefer building the calendar in Power Query or at the source to avoid the cost of a calculated column on every refresh, but the principle is the same.</p>\n<p><strong>The step almost everyone skips: Mark as Date Table</strong></p>\n<p>Creating the table and relating it to the fact isn't enough. You must mark the table as a date table (<code>Mark as date table</code>, pointing to the date column). This does two essential things:</p>\n<ol>\n<li>Tells the engine which column represents temporal continuity, letting time intelligence functions behave deterministically.</li>\n<li>Removes the automatic date hierarchies (Auto Date/Time) tied to fact columns, which bloat the model with a hidden table per date column.</li>\n</ol>\n<p>Without this step, functions like <code>SAMEPERIODLASTYEAR</code> depend on internal heuristics and can diverge between visuals. Marking the table is the difference between reliable time intelligence and a guessing game.</p>\n<p><strong>Measure patterns you'll reuse</strong></p>\n<p>With the table ready and marked, measures become clean and composable:</p>\n<pre><code>Sales YTD = TOTALYTD ( [Total Sales], 'Dim Calendar'[Date] )\n\nSales Prior Year =\nCALCULATE ( [Total Sales], SAMEPERIODLASTYEAR ( 'Dim Calendar'[Date] ) )\n\n% YoY Var =\nDIVIDE ( [Total Sales] - [Sales Prior Year], [Sales Prior Year] )\n\n3M Moving Average =\nAVERAGEX (\n    DATESINPERIOD ( 'Dim Calendar'[Date], MAX ( 'Dim Calendar'[Date] ), -3, MONTH ),\n    [Total Sales]\n)\n</code></pre>\n<p>Notice they all point to the calendar's date column, never to the fact. That's the contract that keeps everything consistent.</p>\n<p><strong>Production pitfalls</strong></p>\n<ul>\n<li><strong>Fiscal year different from calendar year:</strong> if your company closes the year in July, use the fiscal year-end parameter in <code>TOTALYTD ( ..., \"06-30\" )</code> or build your own fiscal columns. Ignoring this produces wrong totals in board reports.</li>\n<li><strong>Auto Date/Time still on:</strong> check the file options and turn it off globally. Leaving it on alongside your calendar doubles memory cost and confuses anyone editing the model.</li>\n<li><strong>Inactive relationship or multiple dates:</strong> models with several relevant dates (order date, delivery date) require role-playing dimensions with <code>USERELATIONSHIP</code> — don't reach for two calendar tables unnecessarily.</li>\n<li><strong>Filtering by a YearMonth text column:</strong> sorting <code>YearMonth</code> alphabetically works because we use <code>YYYY-MM</code> format; if you use <code>MMM/YYYY</code>, configure <code>Sort by column</code> with a numeric column, or months come out unsorted.</li>\n</ul>\n<p><strong>Wrap-up</strong></p>\n<p>DAX time intelligence is powerful, but it's only as reliable as the date table underneath it. A continuous calendar dimension, with a generous range, marked as a date table and with Auto Date/Time turned off, eliminates the single biggest source of wrong numbers in corporate reports. If your company is scaling Power BI models and needs data governance that supports board-level decisions, Dynamic Solucoes helps structure the modeling, DAX and ALM of your analytical layer with confidence.</p>"}},"pageContext":{"slug":"/blog/power-bi-dax-time-intelligence-tabela-calendario/","previousPost":null,"nextPost":{"frontmatter":{"title":"Power Automate: Service Bus para integracoes assincronas em escala"},"fields":{"slug":"/blog/power-automate-azure-service-bus-integracoes-assincronas/"}}}},"staticQueryHashes":["2269431855"]}