ES
ERVIS SEFERI
Finance · Business · Technologie
← Retour · Je partage mes connaissances
IA & Automatisation · Power BI

DAX : le 31 janvier qui s'invite dans la moyenne mobile

DATESINPERIOD recule de quatre-vingt-dix jours, pas de trois mois calendaires. Sur ce grand livre, la fenêtre déborde d'un jour sur janvier — et embarque la paie avec elle.

Dans le cadre de la rubrique « Je partage mes connaissances », je vous propose de comparer deux exercices en DAX, puis de lisser des charges sur plusieurs mois pour lire une tendance plutôt qu'un pic isolé. Le premier geste est courant : poser l'année précédente à côté de l'année en cours. Le second cache un piège qui ne se voit pas à l'écran : la fonction faite pour lisser une moyenne, sur ce jeu de données, renvoie un nombre faux — et parfaitement crédible.

Deux courbes de charges mensuelles, une pour 2025 et une pour 2026, avec l'écart en pourcentage affiché à chaque mois
Un cumul seul ne dit rien. Posé à côté de l'exercice précédent, il raconte une histoire différente chaque mois.

Un cumul seul ne répond à rien

Le cumul depuis janvier dit combien on a dépensé. Il ne dit pas si c'est beaucoup. Un directeur financier qui lit 65 585,50 € de charges cumulées sur quatre mois n'a aucun repère pour juger ce chiffre seul : c'est plus qu'à la même date l'an dernier, moins, pareil ? La seule façon de répondre est de poser l'exercice précédent à côté, mois par mois, avec l'écart en pourcentage. Et un tableau mensuel, même juste, a son propre défaut : chaque mois y est vu seul. Une écriture inhabituelle sur trente jours — une grosse facture, une paie plus lourde qu'ailleurs — suffit à donner l'impression d'un dérapage, ou à l'inverse à masquer un vrai dérapage le mois suivant. Pour juger une tendance plutôt qu'un accident d'un mois, il faut lisser. C'est l'objet de cet article : construire la comparaison N/N-1, puis une moyenne mobile qui absorbe les à-coups sans les cacher — et qui, mal écrite, les cache justement là où il ne fallait pas.

Une table de calendrier qui retient plus qu'une date

Toute fonction d'intelligence temporelle en DAX a besoin d'une vraie table de dates, déclarée comme telle dans le modèle. Le calendrier utilisé ici est généré en DAX plutôt qu'importé : sept cent trente lignes, du 1er janvier 2025 au 31 décembre 2026, avec une colonne IndexMois qui compte les mois en continu — 1 pour janvier 2025, 16 pour avril 2026. Cette colonne paraît redondante avec l'année et le numéro de mois, qui existent déjà dans la même table. Elle ne l'est pas. Elle ne sert qu'une fois dans cet article, mais c'est exactement à ce moment-là qu'elle sauve le calcul.

La comparaison N/N-1, mesure par mesure

Trois mesures suffisent. Le cumul depuis le début de l'exercice :

Charges YTD =
TOTALYTD ( [Charges], Calendrier[Date] )

Le même cumul l'an dernier, à la même date :

Charges N-1 =
CALCULATE ( [Charges], SAMEPERIODLASTYEAR ( Calendrier[Date] ) )

Et l'écart entre les deux :

Ecart N/N-1 % =
VAR Actuel = [Charges]
VAR Precedent = [Charges N-1]
RETURN
DIVIDE ( Actuel - Precedent, Precedent )
Une variable DAX est figée au moment où elle est déclarée. Si Charges N-1 calculait [Charges] dans une variable puis appelait CALCULATE sur cette variable, la mesure garderait la valeur de l'année en cours : CALCULATE ne sait pas changer une valeur déjà servie, seulement refaire un calcul depuis son début. C'est pour cela que Charges N-1 place la mesure elle-même, jamais une variable, à l'intérieur de CALCULATE.
Mois 2026ChargesCharges YTDCharges N-1Écart N/N-1 %
Janvier35 300,5035 300,5028 240,40+25,00 %
Février23 950,0059 250,5022 752,50+5,26 %
Mars2 285,0061 535,502 742,00−16,67 %
Avril4 050,0065 585,503 645,00+11,11 %

Le mois de mars est le seul en amélioration, à −16,67 %. Les trois autres dérapent, jusqu'à +25,00 % en janvier. Sur l'ensemble des quatre mois, le cumul de charges finit 14,30 % au-dessus de l'exercice précédent (65 585,50 € contre 57 379,90 €), quand les produits ne progressent que de 5,97 % sur la même période (23 800,00 € contre 22 460,00 €). Aucun de ces deux chiffres ne se lit dans un cumul seul : il faut la colonne N-1 posée à côté pour les faire apparaître.

La moyenne mobile qu'on croit maîtriser

Le tableau précédent répond à « combien depuis le début, et est-ce plus qu'avant ». Il ne répond pas à « la tendance récente monte-t-elle ou redescend-elle ». Pour cela il faut une moyenne glissante : la moyenne des trois derniers mois, mois courant inclus. La fonction qui semble faite pour ça, et que la documentation présente comme le raccourci naturel, est DATESINPERIOD.

// Cette mesure est fausse sur ce jeu de données
Moyenne 3 mois faux =
AVERAGEX (
    VALUES ( Calendrier[AnneeMois] ),
    CALCULATE (
        [Charges],
        DATESINPERIOD ( Calendrier[Date], MAX ( Calendrier[Date] ), -3, MONTH )
    )
)
La formule DATESINPERIOD avec un encadré rouge autour de l'argument -3, MONTH, et une frise montrant la fenêtre qui déborde sur le 31 janvier
La formule se lit bien. Elle recule de quatre-vingt-dix jours, pas de trois mois calendaires — et rien dans sa syntaxe ne le signale.

Le 31 janvier qui s'invite dans le calcul

DATESINPERIOD compte en jours, pas en mois calendaires. Reculer de trois mois depuis le 30 avril 2026 ne donne pas le 1er février : ça donne le 31 janvier. La fenêtre s'ouvre un jour trop tôt — et ce jour-là n'est pas n'importe lequel. Le 31 janvier porte l'écriture OD-2026-002, la paie de janvier, 32 100,00 € de charges à elle seule, la plus lourde de tout l'exercice. Un mois qui aurait dû rester entièrement en dehors de la fenêtre y entre par sa toute dernière journée. Le résultat de la mesure reste un nombre plausible : rien à l'écran ne dit qu'il est faux, et c'est précisément ce qui rend l'erreur dangereuse.

Deux frises comparant la fenêtre calculée par DATESINPERIOD, qui commence le 31 janvier, et la fenêtre corrigée, qui commence le 1er février
Même intention, deux bornes différentes. Un jour d'écart suffit à faire entrer une écriture qui n'a rien à faire dans le calcul.
Sur ce site, une anomalie comptable se signale ; elle ne se corrige pas en silence dans l'outil de préparation. Le même principe vaut ici, à front renversé : une erreur de bornes ne doit jamais rester invisible sous prétexte que le chiffre qu'elle produit a l'air raisonnable. Un résultat plausible n'est pas un résultat vérifié.

Compter en mois, jamais en jours

La correction tient dans la colonne IndexMois posée au moment de construire le calendrier. Plutôt que de demander à une fonction de reculer d'une durée en jours, on filtre directement sur des index de mois entiers :

Charges moyenne 3 mois =
VAR IdxMax = MAX ( Calendrier[IndexMois] )
RETURN
AVERAGEX (
    FILTER (
        ALL ( Calendrier[IndexMois] ),
        Calendrier[IndexMois] > IdxMax - 3
            && Calendrier[IndexMois] <= IdxMax
    ),
    CALCULATE ( [Charges] )
)

ALL retire le filtre de mois que la ligne du tableau a posé sur IndexMois, pour pouvoir aller chercher les deux mois précédents au lieu de rester bloqué sur le seul mois affiché. Le FILTER qui suit ne garde ensuite que les trois index attendus — ni un jour de plus, ni un jour de moins.

MoisMois entrant dans la moyenneCharges moyenne 3 mois
2026-01nov. 2025 (vide), déc. 2025 (vide), janv. 202635 300,50
2026-02déc. 2025 (vide), janv. 2026, févr. 202629 625,25
2026-03janv., févr., mars 202620 511,83
2026-04févr., mars, avril 202610 095,00

Les mois sans écriture sont ignorés par AVERAGEX, pas comptés pour zéro. C'est pour cela que janvier vaut sa propre valeur — aucun mois avant lui ne porte d'écriture dans ce calendrier, il n'y a donc rien à moyenner avec — et que février est la moyenne de deux mois seulement. La moyenne descend ensuite régulièrement, de 35 300,50 € à 10 095,00 €, à mesure que la paie de janvier sort progressivement de la fenêtre à sa place normale : un mois entier après l'autre, jamais un jour à la fois.

La série continue avec le total qui ne dit pas tout : classer les postes de charges avec RANKX, les peser avec SWITCH, et rapprocher deux tables sans relation avec TREATAS — de quoi faire apparaître, dans un même rapprochement budgétaire, deux anomalies de sens opposé qui se compensent presque exactement.

Versions : article rédigé d'après Power BI Desktop, mise à jour d'août 2026 (interface en français). Les fonctions DAX utilisées (CALCULATE, DIVIDE, ALL, FILTER, TOTALYTD, SAMEPERIODLASTYEAR, DATESINPERIOD) sont disponibles dans les versions actuelles ; les noms de menus peuvent changer au fil des mises à jour mensuelles.