Repository: tobymao/sqlglot

Issue:
timestamp_from_parts signature with date and time input arguments not supported (snowflake)
Snowflake has a version of `timestamp_from_parts` that takes a `date` and a `time` that doesn't seem to be supported yet.

**Fully reproducible code snippet**
```
import sqlglot

sql = """
with

data as (
select '2020-01-01'::date as d, time_from_parts(12,0,0) as t
)

select
 timestamp_from_parts(d, t) as dt
from
  data
"""

sqlglot.parse(sql, dialect="snowflake")
```
<img width="932" alt="image" src="https://github.com/tobymao/sqlglot/assets/991997/eaadd12b-1bd1-4023-ae4c-e8c84566cc48">


**Official Documentation**
https://docs.snowflake.com/en/sql-reference/functions/timestamp_from_parts


Discussion:
Hey, thanks for the report. Will take a look shortly.

Resolving patch:
diff --git a/sqlglot/dialects/snowflake.py b/sqlglot/dialects/snowflake.py
--- a/sqlglot/dialects/snowflake.py
+++ b/sqlglot/dialects/snowflake.py
@@ -331,6 +331,15 @@ def _parse_colon_get_path(
     return this
 
 
+def _parse_timestamp_from_parts(args: t.List) -> exp.Func:
+    if len(args) == 2:
+        # Other dialects don't have the TIMESTAMP_FROM_PARTS(date, time) concept,
+        # so we parse this into Anonymous for now instead of introducing complexity
+        return exp.Anonymous(this="TIMESTAMP_FROM_PARTS", expressions=args)
+
+    return exp.TimestampFromParts.from_arg_list(args)
+
+
 class Snowflake(Dialect):
     # https://docs.snowflake.com/en/sql-reference/identifiers-syntax
     NORMALIZATION_STRATEGY = NormalizationStrategy.UPPERCASE
@@ -423,6 +432,8 @@ class Parser(parser.Parser):
             "SQUARE": lambda args: exp.Pow(this=seq_get(args, 0), expression=exp.Literal.number(2)),
             "TIMEDIFF": _parse_datediff,
             "TIMESTAMPDIFF": _parse_datediff,
+            "TIMESTAMPFROMPARTS": _parse_timestamp_from_parts,
+            "TIMESTAMP_FROM_PARTS": _parse_timestamp_from_parts,
             "TO_TIMESTAMP": _parse_to_timestamp,
             "TO_VARCHAR": exp.ToChar.from_arg_list,
             "ZEROIFNULL": _zeroifnull_to_if,


Test patch:
diff --git a/tests/dialects/test_snowflake.py b/tests/dialects/test_snowflake.py
--- a/tests/dialects/test_snowflake.py
+++ b/tests/dialects/test_snowflake.py
@@ -36,6 +36,7 @@ def test_snowflake(self):
   )""",
         )
 
+        self.validate_identity("SELECT TIMESTAMP_FROM_PARTS(d, t)")
         self.validate_identity("SELECT GET_PATH(v, 'attr[0].name') FROM vartab")
         self.validate_identity("SELECT TO_ARRAY(CAST(x AS ARRAY))")
         self.validate_identity("SELECT TO_ARRAY(CAST(['test'] AS VARIANT))")
@@ -74,6 +75,10 @@ def test_snowflake(self):
         self.validate_identity(
             'DESCRIBE TABLE "SNOWFLAKE_SAMPLE_DATA"."TPCDS_SF100TCL"."WEB_SITE" type=stage'
         )
+        self.validate_identity(
+            "SELECT TIMESTAMPFROMPARTS(d, t)",
+            "SELECT TIMESTAMP_FROM_PARTS(d, t)",
+        )
         self.validate_identity(
             "SELECT user_id, value FROM table_name SAMPLE ($s) SEED (0)",
             "SELECT user_id, value FROM table_name TABLESAMPLE ($s) SEED (0)",
@@ -166,6 +171,16 @@ def test_snowflake(self):
             "CAST(x AS VARCHAR)",
         )
 
+        self.validate_all(
+            "SELECT TIMESTAMP_FROM_PARTS(2013, 4, 5, 12, 00, 00)",
+            read={
+                "duckdb": "SELECT MAKE_TIMESTAMP(2013, 4, 5, 12, 00, 00)",
+            },
+            write={
+                "duckdb": "SELECT MAKE_TIMESTAMP(2013, 4, 5, 12, 00, 00)",
+                "snowflake": "SELECT TIMESTAMP_FROM_PARTS(2013, 4, 5, 12, 00, 00)",
+            },
+        )
         self.validate_all(
             """WITH vartab(v) AS (select parse_json('[{"attr": [{"name": "banana"}]}]')) SELECT GET_PATH(v, '[0].attr[0].name') FROM vartab""",
             write={