Padrão: fuso horário e configuração por localidade

DAX

1. Última atualização no fuso local

No Power BI Service, NOW() e TODAY() devolvem a hora em UTC, e no Power Query Online DateTime.LocalNow() também devolve UTC. Uma medida de "última atualização" com essas funções mostra a hora errada depois de publicada: às 22h de Brasília, o Service já está no dia seguinte.

A solução é gravar o momento do refresh no Power Query, em UTC, e converter para o fuso local de forma explícita. Crie a consulta TabIntAtualizacao:

M
let
    // Momento do refresh em UTC; a versão Fixed mantém o mesmo valor em toda a consulta
    HoraUtc = DateTimeZone.FixedUtcNow(),
    // Converte para o fuso de Brasília (UTC−3) e descarta o fuso depois da conversão
    HoraLocal = DateTimeZone.RemoveZone ( DateTimeZone.SwitchZone ( HoraUtc, -3, 0 ) ),
    Resultado = #table ( type table [ #"Data da Atualização" = datetime ], { { HoraLocal } } )
in
    Resultado
DAX
DEFINE
    MEASURE TabIntAtualizacao[Última Atualização] =
        "Atualizado em "
            & FORMAT ( MAX ( TabIntAtualizacao[Data da Atualização] ), "dd/mm/yyyy hh:nn" )

EVALUATE
{ [Última Atualização] }
  • Atenção O deslocamento -3 é o de Brasília, que não tem horário de verão desde 2019 (Decreto 9.772/2019). O Brasil tem quatro fusos, de UTC−2 a UTC−5: ajuste o valor para usuários de outras regiões.
  • TabIntAtualizacao[Data da Atualização] também serve de "hoje" para medidas como Dias sem Venda e Projeção do Mês (Cookbook, caso 10).

1.1 Farol de frescor do refresh

A medida de última atualização diz quando o modelo foi atualizado; o farol diz se isso é um problema. Compare a data do refresh com o "hoje" no fuso local: atualizado hoje, Atenção ontem, antes de ontem (provável falha no refresh agendado). O formato e o idioma vêm da configuração em cascata (item 3).

DAX
DEFINE
    MEASURE TabIntMedida[Idioma do Projeto] =
        "pt-BR"

    MEASURE TabIntMedida[Formato de Data] =
        SWITCH (
            [Idioma do Projeto],
            "en-US", "ddd mm/dd/yyyy",
            "de-DE", "ddd dd.mm.yyyy",
            "ddd dd/mm/yyyy"
        )

    MEASURE TabIntAtualizacao[Status da Atualização] =
        VAR vMomento = MAX ( TabIntAtualizacao[Data da Atualização] )
        -- DATE ( ANO, MÊS, DIA ) descarta a hora sem passar por texto
        VAR vData = DATE ( YEAR ( vMomento ), MONTH ( vMomento ), DAY ( vMomento ) )
        -- "Hoje" em Brasília: UTCNOW é igual no Desktop e no Service
        VAR vAgora = UTCNOW () - TIME ( 3, 0, 0 )
        VAR vHoje = DATE ( YEAR ( vAgora ), MONTH ( vAgora ), DAY ( vAgora ) )
        VAR vEmoji =
            SWITCH (
                TRUE (),
                vData = vHoje, "✔️",
                vData = vHoje - 1, "⚠️",
                "❗"
            )
        RETURN
            IF (
                NOT ISBLANK ( vMomento ),
                vEmoji & " " & FORMAT ( vMomento, [Formato de Data] & " hh:nn", [Idioma do Projeto] )
            )

EVALUATE
{ [Status da Atualização] }
  • Atenção Não use DATEVALUE numa data e hora: ela espera texto e depende da conversão implícita pela localidade.
  • Refresh só em dia útil: com refresh agendado de segunda a sexta, a segunda-feira mostra para o refresh de sexta. Troque vHoje - 1 pelo último dia útil se isso for esperado.
  • Resultado num modelo real: ✔️ sáb 26/09/2026 16:49.

2. USERCULTURE() e o calendário

USERCULTURE() devolve o idioma de quem está vendo o relatório em medidas, regras de RLS e itens de cálculo. Numa tabela ou coluna calculada em modo Import, ela é avaliada no refresh: o resultado fica fixo e, no refresh agendado, usa uma cultura invariável, e não a de quem abre o relatório.

Por isso o calendário usa uma localidade definida pelo autor do modelo, e não detectada automaticamente.

  • Colunas calculadas com Expression Context = User Context (nível de compatibilidade 1705) são avaliadas na consulta e aceitam USERCULTURE(). Como não são materializadas, não servem para gerar uma tabela calendário.

3. Configuração em cascata: uma medida, vários comportamentos

Uma medida manual guarda a localidade do projeto; as outras derivam dela. Trocar "pt-BR" por "en-US" num só lugar muda idioma, hemisfério, início da semana e formato de data, sem risco de metade do relatório ficar em cada idioma. Nos exemplos, as medidas ficam em TabIntMedida, a tabela de medidas do modelo; qualquer tabela serve.

DAX
DEFINE
    MEASURE TabIntMedida[Idioma do Projeto] =
        "pt-BR"   -- fonte única: troque só aqui

    MEASURE TabIntMedida[Hemisfério do Projeto] =
        -- Por localidade completa: pt-BR e pt-PT têm o mesmo idioma e hemisférios opostos
        SWITCH (
            [Idioma do Projeto],
            "pt-PT", "Norte", "es-ES", "Norte", "en-US", "Norte",
            "fr-FR", "Norte", "de-DE", "Norte", "it-IT", "Norte",
            "Sul"   -- pt-BR, es-AR, en-AU e demais
        )

    MEASURE TabIntMedida[Primeiro Dia da Semana do Projeto] =
        -- Códigos de WEEKNUM: 1 = domingo, 2 = segunda-feira
        SWITCH ( [Idioma do Projeto], "en-US", 1, 2 )

    MEASURE TabIntMedida[Formato de Data] =
        SWITCH (
            [Idioma do Projeto],
            "en-US", "ddd mm/dd/yyyy",
            "de-DE", "ddd dd.mm.yyyy",
            "ddd dd/mm/yyyy"
        )

EVALUATE
ROW (
    "Idioma", [Idioma do Projeto],
    "Hemisfério", [Hemisfério do Projeto],
    "Primeiro dia", [Primeiro Dia da Semana do Projeto],
    "Hoje formatado", FORMAT ( TODAY (), [Formato de Data], [Idioma do Projeto] )
)

As medidas alimentam direto a UDF DataHora.Calendario da Code Library, que já recebe localidade, início da semana e hemisfério:

DAX
TabDimCalendario =
DataHora.Calendario (
    DATE ( 2023, 1, 1 ),
    DATE ( 2026, 12, 31 ),
    [Idioma do Projeto],                  -- nomes de mês, dia e estação
    [Primeiro Dia da Semana do Projeto],  -- WEEKNUM e Semana do Mês
    1,                                    -- ano fiscal começando em janeiro
    [Hemisfério do Projeto]               -- "Norte" ou "Sul": estação do ano
)
  • Tabela calculada pode usar medida: o valor é lido no refresh, sem filtro. Por isso a localidade é uma constante, e não USERCULTURE().
  • Atenção Depois de criar a tabela, marque-a como Tabela de Datas.

4. O mesmo padrão em outros domínios

Moeda de exibição: a medida escolhe o símbolo; para o número manter o tipo numérico no gráfico, aplique-o numa cadeia de formato dinâmica, e não com FORMAT, que transforma o valor em texto.

DAX
DEFINE
    MEASURE TabIntMedida[Moeda do Projeto] =
        "BRL"

    MEASURE TabIntMedida[Formato da Moeda] =
        SWITCH (
            [Moeda do Projeto],
            "USD", "\$#,0.00",
            "EUR", "€ #,0.00",
            "JPY", "¥ #,0",        -- iene sem casas decimais
            "R\$ #,0.00"
        )

EVALUATE
ROW ( "Moeda", [Moeda do Projeto], "Cadeia de formato", [Formato da Moeda] )

Na medida de valor, em Formato › Dinâmico, use [Formato da Moeda] como cadeia de formato.

Unidade de medida: o mesmo esqueleto serve para rótulo e fator de conversão.

DAX
DEFINE
    MEASURE TabIntMedida[Sistema de Unidades] =
        "Métrico"

    MEASURE TabIntMedida[Rótulo de Distância] =
        SWITCH ( [Sistema de Unidades], "Imperial", "mi", "km" )

    MEASURE TabIntMedida[Fator de Distância] =
        SWITCH ( [Sistema de Unidades], "Imperial", 0.621371, 1 )

EVALUATE
ROW ( "Rótulo", [Rótulo de Distância], "Fator", [Fator de Distância] )
  • Atenção Uma medida não troca o agrupamento de um visual: devolver o nome de uma coluna como texto não muda o eixo. Para o leitor escolher a granularidade (dia, semana, mês), use parâmetros de campo.

5. Quando usar a cascata e quando usar um parâmetro

SituaçãoUse
O autor decide uma vez por modelo (template regional, idioma do cliente)Medida em cascata
Três ou mais comportamentos precisam mudar juntosMedida em cascata
O valor precisa chegar a uma tabela calculada, como o calendárioMedida em cascata
O leitor escolhe no relatório, com segmentaçãoParâmetro numérico ou parâmetro de campo

Fontes

Conhecer a trilha Power BI ao vivo