ServicesÀ proposNotesContact Me contacter →
EN FR
Note

Gestion des fuseaux horaires dans l'export GA4 BigQuery

Trois contextes de fuseau horaire coexistent dans les exports GA4 BigQuery — event_timestamp, event_date et _TABLE_SUFFIX utilisent chacun des références différentes qui cassent silencieusement les requêtes de plages de dates.

Planté
ga4bigqueryanalyticsdata engineering

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

ChampFuseau horaireFormat
event_timestampUTCMicrosecondes depuis l’epoch Unix
event_dateFuseau horaire de la propriétéChaîne YYYYMMDD
_TABLE_SUFFIXHeure du PacifiqueChaî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_time
FROM `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 events
FROM `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_name

Le 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_time
FROM `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_micros
FROM {{ 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.