Streamlining your tech stack for maximum efficiency

Learn, explore, and grow with our knowledge hub.

Power BI Refresh Timestamp: Build a Stale-Data Warning
Smart Statistics · Practical Power BI tutorial

Stop stale data driving decisions

Build a visible refresh timestamp, calculate its age and warn users when a report needs checking—before yesterday’s position becomes today’s decision.

Reporting confidence panel Illustrative example · All figures
Ageing refresh: check before use
Refresh age31 h
Review after24 h
Stale after48 h

Example refresh-interval pattern, not measured business performance.

Model audit timestampAvailable
Source completenessSeparate check
Escalation ownerReporting team
The decision risk

A convincing report can still contain old information

A branch manager reviews a sales report before ordering stock. The visuals load normally, but the scheduled import has not run. The numbers look plausible because there is no visible warning. A refresh-age banner gives that manager a reason to pause and contact the owner.

Refresh recency

When was the audit query last evaluated and loaded? This tutorial measures elapsed time since that event.

Source completeness

Has each required source delivered its expected batch? A recent refresh can still load an old file or incomplete extract.

Business approval

Have reconciliations and sign-offs passed? A green refresh-age label cannot approve the report for every decision.

Use this pattern for a conventional Import semantic model that you can edit in Power BI Desktop. It needs a loaded audit query and DAX measures. Live connections and models with selective table or partition processing need a model-specific design. Microsoft describes these different refresh behaviours in its data refresh guidance.
Build the control

Stamp the refresh. Measure the age. Explain the action.

The example policy below uses elapsed hours: review after 24 hours and treat the refresh as stale after 48. These are illustrative settings, not universal service levels.

Create a one-row audit query

In Power BI Desktop, open Transform data. Create a Blank Query, open Advanced Editor and replace its contents with this M code. Name the query RefreshAudit.

let
    EvaluatedAtUTC =
        DateTimeZone.RemoveZone(
            DateTimeZone.FixedUtcNow()
        ),
    Audit = #table(
        type table [RefreshEvaluatedUTC = datetime],
        {{EvaluatedAtUTC}}
    )
in
    Audit

Enable loading and inclusion in report refresh, then choose Close & Apply. Keep the table disconnected: it does not need a relationship to the Date table or business facts.

FixedUtcNow returns a fixed UTC value during evaluation. RemoveZone removes the timezone wrapper so it can be loaded as a Date/Time value. The value remains UTC; removing the wrapper does not convert it to UK local time.

Name it accurately. This is the audit query’s evaluation timestamp, not the exact time the whole refresh completed. A successful audit query alone does not prove that every business table or upstream source is current.

Create the timestamp and age measures

Create these as measures, one at a time. The first requires exactly one audit row and ignores ordinary filters on that table. A missing timestamp or unexpected row count returns blank.

Refresh Evaluated UTC =
VAR AuditRows =
    CALCULATE(
        COUNTROWS('RefreshAudit'),
        REMOVEFILTERS('RefreshAudit')
    )
RETURN
    IF(
        AuditRows = 1,
        CALCULATE(
            MAX('RefreshAudit'[RefreshEvaluatedUTC]),
            REMOVEFILTERS('RefreshAudit')
        )
    )
Refresh Age Hours =
VAR Stamp = [Refresh Evaluated UTC]
RETURN
    IF(
        NOT ISBLANK(Stamp),
        (UTCNOW() - Stamp) * 24
    )

Format the age measure to one decimal place. Keep the underlying value unrounded for threshold comparisons. A negative age remains visible to the status logic rather than being disguised as zero.

REMOVEFILTERS clears the specified filter context; it does not bypass row-level security. UTCNOW supplies a UTC comparison value. The measure is not a continuously running clock: its displayed result depends on query evaluation and caching.

Translate age into a decision message

Add these two measures. Blank and invalid values are handled before the healthy case, so missing evidence never silently becomes a green status.

Refresh Status =
VAR AgeHours = [Refresh Age Hours]
RETURN
    SWITCH(
        TRUE(),
        ISBLANK(AgeHours), "Unknown - check audit data",
        AgeHours < 0, "Invalid - check UTC timestamp",
        AgeHours > 48, "Stale - confirm before use",
        AgeHours > 24, "Ageing - review refresh",
        "Within refresh-age threshold"
    )
Refresh Banner =
VAR Stamp = [Refresh Evaluated UTC]
RETURN
    [Refresh Status]
        & IF(
            ISBLANK(Stamp),
            " | No valid audit timestamp",
            " | Audit evaluated: "
                & FORMAT(Stamp, "dd MMM yyyy HH:mm")
                & " UTC"
        )

Put Refresh Banner in a prominent card near the report title and Refresh Age Hours in a nearby numeric card. Keep the warning text visible even if you also apply conditional colours. Add the reporting team’s agreed contact route alongside it.

Exactly 24 hours remains within the example threshold. Exactly 48 hours remains ageing. Change the comparison operators if your policy requires warnings at, rather than after, those boundaries.

Test the failure cases before publishing

Use a development copy of the model to test known timestamps. Restore the dynamic query afterwards. This table states the expected results for the example policy.

Illustrative test cases
Audit conditionExpected statusOwner action
No row, blank timestamp or multiple rowsUnknownRepair the audit query
Timestamp in the futureInvalidCheck UTC handling and clock
Age from 0 through 24 hoursWithin thresholdApply separate source checks
Age above 24 through 48 hoursAgeingReview the refresh schedule/history
Age above 48 hoursStaleConfirm suitability before use

After publishing, run the normal semantic-model refresh and check its history, the loaded audit timestamp and the report banner. Confirm that business slicers do not change the timestamp. Re-query or reopen the report when verifying age; an untouched browser tab is not an alerting system.

If your process refreshes individual tables or partitions, verify that the audit table and required business data are covered. Do not adopt this timestamp as a blanket success signal for partial processing.

Keep the meaning honest

Three rules for trustworthy warnings

Keep UTC explicit

Store and compare in UTC. If you display UK local time, use a deliberate GMT/BST conversion. Adding one hour permanently is wrong for part of the year.

Check upstream delivery

For each required source, record an expected batch, received batch and completeness result. A maximum transaction date alone cannot prove that every expected record arrived.

Assign a response owner

Agree who investigates, who communicates the limitation and who approves continued use. Weekend exceptions need a business calendar, not just a larger elapsed-hour limit.

Interactive release check

Will users know when to pause?

This checklist measures implementation readiness. It is not connected to your Power BI environment.

Implementation readiness

0 of 5

Select the checks you have completed.

Measure the outcome. Track stale-report incidents, time to acknowledge a warning and time to restore a usable report. Set a baseline before claiming improvement.
Practical questions

Power BI refresh-age FAQs

Does a recent timestamp prove the data is complete?

No. It shows when the audit query was evaluated and loaded. Source batch completeness and business reconciliation need separate checks.

Will the age update every second?

No. UTCNOW is evaluated when the measure runs, and caching can affect what users see. This report banner is not a continuously running clock or an external alert.

Should I use a calculated column for refresh age?

Use a measure for this pattern. A stored calculated column would keep its computed age until it is recalculated, making it unsuitable for a query-time comparison.

Will this work unchanged with a live connection?

No. The tutorial assumes an editable Import semantic model. A live-connected report needs the appropriate audit data and measures supplied by its underlying model.

Are 24 and 48 hours the right thresholds?

They are illustrative elapsed-hour thresholds. Agree limits with the business owner and account for reporting cadence, operating days and the decision being supported.

Does the banner stop someone using stale numbers?

No. It is a visible warning, not an access restriction. The team still needs an agreed response process and separate operational monitoring.

Give every report a clear signal about the age of its information

Smart Statistics helps UK businesses improve Power BI reporting, data checks and operational ownership. Start with one important report, make its limitations visible and agree what happens when a warning appears.

Technical references

Microsoft documentation checked on 17 September 2026. The warning policy and implementation checklist are illustrative Smart Statistics examples.