Saturday
Hi Databricks Community,
I'm facing a timezone-related issue with a Unity Catalog Foreign Catalog connected to AWS RDS PostgreSQL and would appreciate some guidance on the best way to handle it centrally.
Current Setup:
Source: AWS RDS PostgreSQL (configured in Central Time / CST)
Databricks: Unity Catalog Foreign Catalog using Lakehouse Federation
Foreign Catalog: Appears to interpret timestamps in UTC by default
Issue:
When querying the foreign catalog from Databricks, I've noticed discrepancies in query results involving date filters and aggregations compared to running equivalent queries directly against PostgreSQL.
For example, queries using date ranges, daily aggregations, or timestamp-based filtering return different counts or totals.
Even after setting the session timezone in the Databricks SQL Editor, the results remain inconsistent.
The only workaround I've found is to explicitly convert or cast timestamps to Central Time within each SQL query, which produces the expected results.
However, this isn't scalable, especially when multiple users, dashboards, and downstream applications consume the same foreign catalog.
What I'm Trying to Achieve:
I'd like to handle timezone interpretation or conversion centrally so that consumers get consistent results without needing to remember timezone conversions in every query.
Questions for the Community:
Is there a supported way to configure the timezone at the Unity Catalog Foreign Catalog, connection, or federation level?
Does Lakehouse Federation support passing a timezone setting to the underlying PostgreSQL session?
Would a Databricks SQL warehouse-level configuration help, or does federated query execution behave differently?
Is the recommended approach to use governed views that standardize timestamp conversions, or is there a better native solution?
Ideally, I'd like to preserve the correct source timestamps while ensuring consistent business-date filtering and aggregation across all consumers.
Has anyone encountered this behavior with AWS RDS PostgreSQL and Databricks Lakehouse Federation? How did you resolve it without requiring query-level timezone conversions?
Thanks in advance for your insights!
Tags: Databricks SQL, Unity Catalog, Lakehouse Federation, PostgreSQL, Timezone, AWS RDS, Data Governance
Saturday
Short version: I could not find a documented timezone setting at the foreign catalog, connection or warehouse level, so I would plan on fixing it once in a governed layer rather than per query. Treat the details below as things to verify on your side.
1) Check the Postgres column type first. The federation docs map 'timestamp without time zone' to either TIMESTAMP or TIMESTAMP_NTZ depending on a preferTimestampNTZ flag (default false, so TIMESTAMP), and I did not find a documented way to set that flag on a foreign catalog. A 'timestamp without time zone' column that holds Central wall-clock values will then be read as if it were an instant, which is where date-filter and daily-aggregation drift comes from. A 'timestamptz' column carries an absolute instant and is usually fine once the session time zone is set.
2) Quick diagnosis on one known row: compare SELECT ts, ts::text in Postgres against SELECT ts, CAST(ts AS STRING), typeof(ts) in Databricks (via the foreign catalog). If the wall-clock text is the same but the type is TIMESTAMP, the session time zone setting will not change how the value is read, which would explain why SET TIME ZONE did not help.
3) Fix it centrally with a thin view layer. For each federated table, create a view in a curated schema that does the conversion once, e.g. to_utc_timestamp(ts, 'America/Chicago') as event_ts_utc (treats the stored wall-clock value as Central and gives you the true instant) and CAST(ts AS DATE) as business_date computed from the original wall-clock value. Point dashboards and downstream apps at the views only, and grant no access to the raw foreign catalog. Using the IANA zone name rather than a fixed CST offset keeps daylight saving correct.
4) If the data is queried a lot, a scheduled materialized copy of those views avoids both repeated conversion and repeated hits on RDS, and the business_date column then becomes a plain stored value everyone filters on.
One more check: confirm the RDS parameter group time zone and the session timezone Databricks opens its connection with, since a mismatch there changes how timestamptz values are rendered on the way out. If you can share the column type and one example row from each side, it will be easy to say which case you are in.
Sunday
Monday
I spent some time reproducing a similar scenario using Neon PostgreSQL connected to Databricks through Unity Catalog Lakehouse Federation and found a few observations that might help explain the timezone/date-aggregation mismatch.
I created a PostgreSQL table containing both timestamp types:
CREATE TABLE timezone_test.events (
id INTEGER PRIMARY KEY,
event_description TEXT,
local_timestamp TIMESTAMP WITHOUT TIME ZONE,
utc_timestamp TIMESTAMP WITH TIME ZONE
);Inserted six test records around America/Chicago midnight boundaries and daylight-saving transitions (March 8 and November 1, 2026).
PostgreSQL correctly handled both UTC and Chicago timezone conversions. For example:
Source timestamp (Chicago) UTC instant Chicago date
| 2026-03-07 23:30 | 2026-03-08 05:30 UTC | Mar 7 |
| 2026-03-08 00:30 | 2026-03-08 06:30 UTC | Mar 8 |
| 2026-03-08 03:30 | 2026-03-08 08:30 UTC | Mar 8 |
This established the source-side baseline before testing federation.
I created a PostgreSQL connection and foreign catalog in Databricks, then queried the same six records.
One important observation: both PostgreSQL timestamp types were exposed as Databricks TIMESTAMP by default.
With:
SET TIME ZONE 'America/Chicago';the PostgreSQLtimestamp without time zone values were displayed differently in Databricks.
For example:
The underlying epoch remained unchanged across Databricks UTC and Chicago sessions, confirming that the mapped value was being treated as an instant rather than preserving the original local wall-clock representation.
I compared the same date aggregation against:
Interestingly, the foreign catalog returned different date groupings from the native Delta table.
EXPLAIN FORMATTED confirmed that the foreign-catalog query pushed the date casts and aggregation directly to PostgreSQL:
SELECT
CAST("local_timestamp" AS DATE),
CAST("utc_timestamp" AS DATE),
COUNT(*)
FROM "timezone_test"."events"
GROUP BY
CAST("local_timestamp" AS DATE),
CAST("utc_timestamp" AS DATE)For example, three records were grouped under March 8 for the PostgreSQL local timestamp, whereas Databricks-local evaluation grouped those same records under March 7.
This demonstrates how timestamp mapping combined with aggregate pushdown can produce different business-day groupings.
An additional observation regarding timezone configuration: although SET TIME ZONE 'America/Chicago' changed the Databricks session's timestamp interpretation, it did not ensure equivalent date-casting semantics when aggregation was pushed to PostgreSQL.
EXPLAIN FORMATTED confirmed that date casts and aggregation executed remotely in PostgreSQL. When I disabled aggregate pushdown through reomte_query(), the date conversions and grouping executed locally in Photon, producing results consistent with the native Delta table.
This suggests that configuring the Databricks SQL session or warehouse timezone alone may not resolve discrepancies involving remote execution.
A. Disable aggregate pushdown
SELECT
CAST(local_timestamp AS DATE) AS local_date,
COUNT(*) AS records
FROM remote_query(
'neon_postgres_connection',
database => 'neondb',
query => 'SELECT local_timestamp FROM timezone_test.events',
`pushdown.aggregates.enabled` => 'false',
`pushdown.filters.enabled` => 'false'
)
GROUP BY CAST(local_timestamp AS DATE)This successfully produced results consistent with the native Delta table.
EXPLAIN FORMATTED also confirmed that Photon performed the date conversion and aggregation locally, rather than pushing them to PostgreSQL.
This is a useful workaround, although it may affect performance and does not necessarily preserve the original PostgreSQL business-date semantics.
B. Preserve source timestamps using TIMESTAMP_NTZ
An explicit CAST(local_timestamp AS TIMESTAMP_NTZ) after federation did not restore the original PostgreSQL wall-clock values.
However, converting the timestamp to text in PostgreSQL first, then casting to TIMESTAMP_NTZ in Databricks, worked:
SELECT
id,
CAST(local_ts_text AS TIMESTAMP_NTZ) AS local_ntz
FROM remote_query(
'neon_postgres_connection',
database => 'neondb',
query => '
SELECT id,
local_timestamp::text AS local_ts_text
FROM timezone_test.events
'
)This preserved the original PostgreSQL values, including 2026-03-08 00:30:00 without the earlier Chicago display shift.
This workaround is specifically relevant to PostgreSQL timestamp without time zone columns representing local wall-clock values, not timestamptz columns representing actual instants.
The Databricks PostgreSQL federation documentation mentions preferTimestampNTZ=true for mapping PostgreSQL timezone-naive timestamps to TimestampNTZType.
I checked foreign catalog connection and couldn't find a way to specify it through the connection.
Based on this controlled reproduction, the interaction between PostgreSQL timestamp type mapping and federated aggregate pushdown can lead to different date-aggregation results, even under the same Databricks session timezone.
The tests demonstrated two practical approaches depending on the intended semantics:
Neither should be treated as a universal fix without validating the source timestamp semantics.
Also another community post highlighting the same issue and narrowed down to the same governed view approach to encapsulate remote_query or source-side text-to-TIMESTAMP_NTZ conversion
It would also be valuable for Databricks to clarify timezone handling and document the availability of preferTimestampNTZ for Unity Catalog federation. I tried Altering the foreign catalog to set this property but it complains does not support the following option(s): preferTimestampNTZ.
Monday
Agree there's no timezone option on the connection or foreign catalog. Rather than casting in every query, I'd fix it once in a governed view:
CREATE VIEW main.gold.orders_v AS
SELECT
order_id,
to_utc_timestamp(created_at, 'America/Chicago') AS created_at_utc,
CAST(created_at AS TIMESTAMP_NTZ) AS created_at_local
FROM pg_catalog.public.orders;
Grant SELECT on the view only, not the foreign catalog. That way every consumer (SQL, dashboards, Genie) gets the same answer.
Three things to watch:
- Use 'America/Chicago', not a fixed -06:00 offset, so daylight saving time is handled. DST ends Sunday 1 Nov, so the 01:00–02:00 hour that day happens twice and can't be told apart in a timestamp-without-time-zone column.
- Wrapping the column in a function can stop the filter from being pushed down to Postgres. Check EXPLAIN. If the filter isn't pushed down, also filter on the raw column with a one-day buffer.
- If you can change the source, timestamptz in Postgres avoids the whole problem.