Daily Participation + conversion window: broken SQL on Redshift due to TIMESTAMP type mismatch
Describe the bug
The Daily Participation metric type generates invalid SQL on Redshift when a conversion window is configured. Without a conversion window this issue does not occur. When a conversion window is set, the __userMetricAgg CTE casts the exposure timestamp to TIMESTAMP WITHOUT TIME ZONE using CAST(MIN(umj.timestamp) AS TIMESTAMP), then passes it into LEAST() alongside CURRENT_TIMESTAMP, which Redshift always returns as TIMESTAMP WITH TIME ZONE (TIMESTAMPTZ). This causes a type mismatch that Redshift cannot resolve, and the query fails.
Error message:
function pg_catalog.date_diff("unknown", timestamp without time zone, timestamp with time zone) does not exist
Steps to reproduce
- Create a Daily Participation fact metric with a 7-day conversion window
- Add it to any experiment
- Run the experiment results query against a Redshift data source
- Query fails with the above error
Generated SQL (problematic section):
__userMetricAgg as (
SELECT
umj.variation,
umj.user_id,
COUNT(DISTINCT umj.m0_value)::float / GREATEST(
datediff(
day,
CAST(MIN(umj.timestamp) AS TIMESTAMP), -- ← strips timezone, returns TIMESTAMP
LEAST(
CURRENT_TIMESTAMP, -- ← always TIMESTAMPTZ on Redshift
CAST(MIN(umj.timestamp) AS TIMESTAMP) + INTERVAL '168 hours'
)
) + 1,
1
)::float AS m0_value
FROM __userMetricJoin umj
GROUP BY umj.variation, umj.user_id
)
Expected behaviour
The query runs successfully and returns Daily Participation results.
Actual behaviour
Query fails with:
function pg_catalog.date_diff("unknown", timestamp without time zone, timestamp with time zone) does not exist
Proposed fixRemove the explicit CAST(... AS TIMESTAMP) calls so the timestamp retains its original type (TIMESTAMPTZ) throughout, making it consistent with CURRENT_TIMESTAMP:
__userMetricAgg as (
SELECT
umj.variation,
umj.user_id,
COUNT(DISTINCT umj.m0_value)::float / GREATEST(
datediff(
day,
MIN(umj.timestamp),
LEAST(
CURRENT_TIMESTAMP,
MIN(umj.timestamp) + INTERVAL '168 hours'
)
) + 1,
1
)::float AS m0_value
FROM __userMetricJoin umj
GROUP BY umj.variation, umj.user_id
)Environment
Data source: Amazon Redshift Metric type: Daily Participation Assignment query timestamp column: collector_tstamp (Snowplow unified events table, stored as UTC)
Source: growthbook/growthbook