Repository: tobymao/sqlglot

Issue:
`time_to_str` call is incorrect for tsql
```
In [9]: import sqlglot as sg

In [10]: sg.__version__
Out[10]: '20.5.0'

In [11]: expr = sg.parse_one("select strftime(a, concat('%Y', '%m'))", read="duckdb")

In [12]: expr.sql("tsql")
Out[12]: "SELECT FORMAT(a, 'None')"
```

Other dialects seem to work fine:

```
In [13]: expr.sql("snowflake")
Out[13]: "SELECT TO_CHAR(CAST(a AS TIMESTAMPNTZ), CONCAT(COALESCE('yyyy', ''), COALESCE('mm', '')))"
```



Discussion:

Resolving patch:
diff --git a/sqlglot/dialects/tsql.py b/sqlglot/dialects/tsql.py
--- a/sqlglot/dialects/tsql.py
+++ b/sqlglot/dialects/tsql.py
@@ -140,23 +140,23 @@ def _parse_hashbytes(args: t.List) -> exp.Expression:
 
 
 def _format_sql(self: TSQL.Generator, expression: exp.NumberToStr | exp.TimeToStr) -> str:
-    fmt = (
-        expression.args["format"]
-        if isinstance(expression, exp.NumberToStr)
-        else exp.Literal.string(
-            format_time(
-                expression.text("format"),
-                t.cast(t.Dict[str, str], TSQL.INVERSE_TIME_MAPPING),
-            )
-        )
-    )
+    fmt = expression.args["format"]
 
-    # There is no format for "quarter"
-    name = fmt.name.upper()
-    if name in DATEPART_ONLY_FORMATS:
-        return self.func("DATEPART", name, expression.this)
+    if not isinstance(expression, exp.NumberToStr):
+        if fmt.is_string:
+            mapped_fmt = format_time(fmt.name, TSQL.INVERSE_TIME_MAPPING)
+
+            name = (mapped_fmt or "").upper()
+            if name in DATEPART_ONLY_FORMATS:
+                return self.func("DATEPART", name, expression.this)
+
+            fmt_sql = self.sql(exp.Literal.string(mapped_fmt))
+        else:
+            fmt_sql = self.format_time(expression) or self.sql(fmt)
+    else:
+        fmt_sql = self.sql(fmt)
 
-    return self.func("FORMAT", expression.this, fmt, expression.args.get("culture"))
+    return self.func("FORMAT", expression.this, fmt_sql, expression.args.get("culture"))
 
 
 def _string_agg_sql(self: TSQL.Generator, expression: exp.GroupConcat) -> str:


Test patch:
diff --git a/tests/dialects/test_duckdb.py b/tests/dialects/test_duckdb.py
--- a/tests/dialects/test_duckdb.py
+++ b/tests/dialects/test_duckdb.py
@@ -195,6 +195,13 @@ def test_duckdb(self):
         self.validate_all("0x1010", write={"": "0 AS x1010"})
         self.validate_all("x ~ y", write={"duckdb": "REGEXP_MATCHES(x, y)"})
         self.validate_all("SELECT * FROM 'x.y'", write={"duckdb": 'SELECT * FROM "x.y"'})
+        self.validate_all(
+            "SELECT STRFTIME(CAST('2020-01-01' AS TIMESTAMP), CONCAT('%Y', '%m'))",
+            write={
+                "duckdb": "SELECT STRFTIME(CAST('2020-01-01' AS TIMESTAMP), CONCAT('%Y', '%m'))",
+                "tsql": "SELECT FORMAT(CAST('2020-01-01' AS DATETIME2), CONCAT('yyyy', 'MM'))",
+            },
+        )
         self.validate_all(
             "SELECT * FROM produce PIVOT(SUM(sales) FOR quarter IN ('Q1', 'Q2'))",
             read={
diff --git a/tests/dialects/test_tsql.py b/tests/dialects/test_tsql.py
--- a/tests/dialects/test_tsql.py
+++ b/tests/dialects/test_tsql.py
@@ -1318,27 +1318,45 @@ def test_format(self):
 
         self.validate_all(
             "SELECT FORMAT(1000000.01,'###,###.###')",
-            write={"spark": "SELECT FORMAT_NUMBER(1000000.01, '###,###.###')"},
+            write={
+                "spark": "SELECT FORMAT_NUMBER(1000000.01, '###,###.###')",
+                "tsql": "SELECT FORMAT(1000000.01, '###,###.###')",
+            },
         )
         self.validate_all(
             "SELECT FORMAT(1234567, 'f')",
-            write={"spark": "SELECT FORMAT_NUMBER(1234567, 'f')"},
+            write={
+                "spark": "SELECT FORMAT_NUMBER(1234567, 'f')",
+                "tsql": "SELECT FORMAT(1234567, 'f')",
+            },
         )
         self.validate_all(
             "SELECT FORMAT('01-01-1991', 'dd.mm.yyyy')",
-            write={"spark": "SELECT DATE_FORMAT('01-01-1991', 'dd.mm.yyyy')"},
+            write={
+                "spark": "SELECT DATE_FORMAT('01-01-1991', 'dd.mm.yyyy')",
+                "tsql": "SELECT FORMAT('01-01-1991', 'dd.mm.yyyy')",
+            },
         )
         self.validate_all(
             "SELECT FORMAT(date_col, 'dd.mm.yyyy')",
-            write={"spark": "SELECT DATE_FORMAT(date_col, 'dd.mm.yyyy')"},
+            write={
+                "spark": "SELECT DATE_FORMAT(date_col, 'dd.mm.yyyy')",
+                "tsql": "SELECT FORMAT(date_col, 'dd.mm.yyyy')",
+            },
         )
         self.validate_all(
             "SELECT FORMAT(date_col, 'm')",
-            write={"spark": "SELECT DATE_FORMAT(date_col, 'MMMM d')"},
+            write={
+                "spark": "SELECT DATE_FORMAT(date_col, 'MMMM d')",
+                "tsql": "SELECT FORMAT(date_col, 'MMMM d')",
+            },
         )
         self.validate_all(
             "SELECT FORMAT(num_col, 'c')",
-            write={"spark": "SELECT FORMAT_NUMBER(num_col, 'c')"},
+            write={
+                "spark": "SELECT FORMAT_NUMBER(num_col, 'c')",
+                "tsql": "SELECT FORMAT(num_col, 'c')",
+            },
         )
 
     def test_string(self):