L’export BigQuery de GA4 contient trois références de fuseau horaire différentes, et elles ne concordent pas entre elles. Des requêtes qui semblent correctes incluront ou excluront silencieusement des événements aux limites de journée, produisant des résultats qui diffèrent de l’interface GA4 sans explication évidente.
Les trois contextes de fuseau horaire
| Champ | Fuseau horaire | Format |
|---|---|---|
event_timestamp | UTC | Microsecondes depuis l’epoch Unix |
event_date | Fuseau horaire de la propriété | Chaîne YYYYMMDD |
_TABLE_SUFFIX | Heure du Pacifique | Chaîne YYYYMMDD |
Chaque champ est cohérent en interne. Le problème survient lorsque vous les mélangez dans une seule requête.
event_timestamp : toujours UTC
Le champ timestamp enregistre quand l’événement s’est produit en Temps Universel Coordonné, stocké en microsecondes depuis l’epoch Unix. Pour le convertir en heure lisible, utilisez les fonctions timestamp et datetime de BigQuery :
SELECT TIMESTAMP_MICROS(event_timestamp) AS event_utc_timestamp, DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Europe/Paris') AS event_paris_time, DATETIME(TIMESTAMP_MICROS(event_timestamp), 'America/New_York') AS event_ny_timeFROM `project.analytics_123456789.events_*`Si vous construisez une table d’événements sessionisés, choisissez un fuseau horaire canonique pour votre équipe et convertissez-le dans la couche de base. Centraliser cette décision évite que chaque analyste applique sa propre conversion et obtienne des résultats différents.
event_date : fuseau horaire de la propriété
Le champ event_date utilise le fuseau horaire configuré de votre propriété GA4, stocké sous forme de chaîne YYYYMMDD (ex. 20260127). Si votre propriété est configurée pour Europe/Paris et qu’un événement se produit à 23h30 UTC le 26 janvier, cet événement obtient event_date = '20260127' — car il est déjà le 27 janvier à Paris.
C’est en fait utile : event_date s’aligne sur ce que votre entreprise considère comme « aujourd’hui », ce qui en fait le champ de partition naturel pour l’analyse. Mais cela crée une subtilité : event_date et la date UTC de event_timestamp peuvent différer d’un jour pour les événements proches de minuit.
_TABLE_SUFFIX : heure du Pacifique
La notation wildcard des tables events_* repose sur _TABLE_SUFFIX pour filtrer les tables date-shardées, mais le suffixe suit l’heure du Pacifique (le fuseau horaire du siège de Google), pas UTC et pas le fuseau horaire de votre propriété.
La conséquence pratique : si le fuseau horaire de votre propriété est Europe/Berlin (UTC+1), un événement se produisant à minuit le 27 janvier heure de Berlin s’est en réalité produit à 23h00 UTC le 26 janvier — ce qui tombe le 26 janvier en heure du Pacifique. L’event_date de cet événement est 20260127 mais sa table est events_20260126.
-- Cette requête peut manquer des événements attendus-- pour une propriété européenne avec des événements du 31 décembre :WHERE _TABLE_SUFFIX = '20261231' AND event_date = '20261231'-- Certains événements du 1er janvier (en fuseau horaire de la propriété)-- se trouvent dans la table du 31 décembre (en heure du Pacifique)Approches pratiques pour les requêtes
Utiliser _TABLE_SUFFIX pour le filtrage de plage
Filtrez toujours _TABLE_SUFFIX pour éviter de scanner l’intégralité de votre dataset. Pour la correction aux limites de date, élargissez votre plage de suffixes d’un jour dans chaque direction :
SELECT event_name, COUNT(*) AS eventsFROM `project.analytics_123456789.events_*`WHERE _TABLE_SUFFIX BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 31 DAY)) AND FORMAT_DATE('%Y%m%d', CURRENT_DATE()) -- Puis filtrer sur event_date pour la plage de dates réelle souhaitée : AND event_date BETWEEN FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 30 DAY)) AND FORMAT_DATE('%Y%m%d', DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY))GROUP BY event_nameLe filtre _TABLE_SUFFIX réduit le coût de scan. Le filtre event_date assure la correction. Utiliser les deux ensemble constitue le pattern robuste.
Filtrer par heure de la journée
Lorsque vous devez filtrer des événements sur une fenêtre horaire locale spécifique, convertissez event_timestamp explicitement :
SELECT event_name, DATETIME(TIMESTAMP_MICROS(event_timestamp), 'America/Chicago') AS local_timeFROM `project.analytics_123456789.events_*`WHERE _TABLE_SUFFIX = '20260127' AND DATETIME(TIMESTAMP_MICROS(event_timestamp), 'America/Chicago') BETWEEN '2026-01-27 09:00:00' AND '2026-01-27 17:00:00'Standardiser dans votre modèle de base
Dans un modèle de base dbt, standardisez toutes les représentations temporelles à la source :
SELECT event_date, TIMESTAMP_MICROS(event_timestamp) AS event_timestamp_utc, DATETIME(TIMESTAMP_MICROS(event_timestamp), '{{ var("property_timezone") }}') AS event_datetime_local, DATE(DATETIME(TIMESTAMP_MICROS(event_timestamp), '{{ var("property_timezone") }}')) AS event_date_local, -- Conserver l'original pour référence event_timestamp AS event_timestamp_microsFROM {{ source('ga4', 'events') }}WHERE _TABLE_SUFFIX BETWEEN ...Stocker les valeurs converties dans le modèle de base signifie que chaque requête en aval obtient des timestamps cohérents et pré-convertis sans répéter la logique TIMESTAMP_MICROS et DATETIME.
Le pattern d’erreur courant
Le scénario qui pénalise le plus souvent : on filtre pour « les données du mois dernier » et les comptages ne correspondent pas à l’interface GA4. L’écart est souvent un problème de limite de journée — _TABLE_SUFFIX filtré trop étroitement, coupant des événements du premier ou dernier jour parce que ces événements se trouvaient dans une table adjacente en raison des différences de fuseau horaire.
Si vous travaillez avec une propriété en UTC, le problème de fuseau horaire disparaît largement : les trois références concordent (à quelques heures près en heure du Pacifique depuis UTC). Les propriétés en UTC+8 à UTC+14 sont les plus exposées car leur « lendemain » en heure locale est encore le « jour en cours » en heure du Pacifique pendant de nombreuses heures.
La correction est mécanique : utilisez toujours event_date pour le filtrage logique par date métier, utilisez _TABLE_SUFFIX uniquement pour le contrôle des coûts avec une fenêtre légèrement plus large que votre plage de dates réelle, et documentez le fuseau horaire de votre propriété dans les variables du projet dbt afin que le modèle de base gère correctement la conversion.