From 25f7df838b6dc2aa81c0e9f55aad61b8903b1b44 Mon Sep 17 00:00:00 2001 From: vaggelisd Date: Tue, 29 Oct 2024 14:27:34 +0200 Subject: [PATCH] feat(snowflake): Transpile BQ's TIMESTAMP() function --- sqlglot/dialects/dialect.py | 5 ++--- sqlglot/dialects/presto.py | 1 + sqlglot/dialects/snowflake.py | 2 ++ tests/dialects/test_bigquery.py | 9 +++++++++ tests/dialects/test_presto.py | 7 ------- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/sqlglot/dialects/dialect.py b/sqlglot/dialects/dialect.py index 97b5628689..dd4ab61633 100644 --- a/sqlglot/dialects/dialect.py +++ b/sqlglot/dialects/dialect.py @@ -1210,9 +1210,8 @@ def no_timestamp_sql(self: Generator, expression: exp.Timestamp) -> str: return self.sql(exp.cast(expression.this, target_type)) if zone.name.lower() in TIMEZONES: return self.sql( - exp.AtTimeZone( - this=exp.cast(expression.this, exp.DataType.Type.TIMESTAMP), - zone=zone, + exp.ConvertTimezone( + source_tz=zone, target_tz=exp.Literal.string("UTC"), timestamp=expression.this ) ) return self.func("TIMESTAMP", expression.this, zone) diff --git a/sqlglot/dialects/presto.py b/sqlglot/dialects/presto.py index 5a3381c0c3..2173d3e5ee 100644 --- a/sqlglot/dialects/presto.py +++ b/sqlglot/dialects/presto.py @@ -336,6 +336,7 @@ class Generator(generator.Generator): exp.DataType.Type.STRUCT: "ROW", exp.DataType.Type.TEXT: "VARCHAR", exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP", + exp.DataType.Type.TIMESTAMPNTZ: "TIMESTAMP", exp.DataType.Type.TIMETZ: "TIME", } diff --git a/sqlglot/dialects/snowflake.py b/sqlglot/dialects/snowflake.py index 18a3d2c9af..ea5680d963 100644 --- a/sqlglot/dialects/snowflake.py +++ b/sqlglot/dialects/snowflake.py @@ -23,6 +23,7 @@ var_map_sql, map_date_part, no_safe_divide_sql, + no_timestamp_sql, ) from sqlglot.helper import flatten, is_float, is_int, seq_get from sqlglot.tokens import TokenType @@ -840,6 +841,7 @@ class Generator(generator.Generator): ), exp.Stuff: rename_func("INSERT"), exp.TimeAdd: date_delta_sql("TIMEADD"), + exp.Timestamp: no_timestamp_sql, exp.TimestampDiff: lambda self, e: self.func( "TIMESTAMPDIFF", e.unit, e.expression, e.this ), diff --git a/tests/dialects/test_bigquery.py b/tests/dialects/test_bigquery.py index d8c6f7f3a0..c59881fe24 100644 --- a/tests/dialects/test_bigquery.py +++ b/tests/dialects/test_bigquery.py @@ -371,9 +371,18 @@ def test_bigquery(self): write={ "bigquery": "TIMESTAMP(x)", "duckdb": "CAST(x AS TIMESTAMPTZ)", + "snowflake": "CAST(x AS TIMESTAMPTZ)", "presto": "CAST(x AS TIMESTAMP WITH TIME ZONE)", }, ) + self.validate_all( + "SELECT TIMESTAMP('2008-12-25 15:30:00', 'America/Los_Angeles')", + write={ + "bigquery": "SELECT TIMESTAMP('2008-12-25 15:30:00', 'America/Los_Angeles')", + "duckdb": "SELECT CAST('2008-12-25 15:30:00' AS TIMESTAMP) AT TIME ZONE 'America/Los_Angeles' AT TIME ZONE 'UTC'", + "snowflake": "SELECT CONVERT_TIMEZONE('America/Los_Angeles', 'UTC', '2008-12-25 15:30:00')", + }, + ) self.validate_all( "SELECT SUM(x IGNORE NULLS) AS x", read={ diff --git a/tests/dialects/test_presto.py b/tests/dialects/test_presto.py index 4c10a45944..31a078c17c 100644 --- a/tests/dialects/test_presto.py +++ b/tests/dialects/test_presto.py @@ -414,13 +414,6 @@ def test_time(self): "CAST(x AS TIMESTAMP)", read={"mysql": "TIMESTAMP(x)"}, ) - self.validate_all( - "TIMESTAMP(x, 'America/Los_Angeles')", - write={ - "duckdb": "CAST(x AS TIMESTAMP) AT TIME ZONE 'America/Los_Angeles'", - "presto": "AT_TIMEZONE(CAST(x AS TIMESTAMP), 'America/Los_Angeles')", - }, - ) # this case isn't really correct, but it's a fall back for mysql's version self.validate_all( "TIMESTAMP(x, '12:00:00')",