Skip to content

Commit

Permalink
fix(clickhouse): fix truncating to date from a timestamp (#10220)
Browse files Browse the repository at this point in the history
  • Loading branch information
cpcloud authored Sep 25, 2024
1 parent d3496fd commit 24e5395
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
SELECT
toStartOfDay(parseDateTimeBestEffort('2009-05-17T12:34:56')) AS "TimestampTruncate(datetime.datetime(2009, 5, 17, 12, 34, 56), DAY)"
CAST(toStartOfDay(parseDateTimeBestEffort('2009-05-17T12:34:56')) AS Nullable(DateTime)) AS "TimestampTruncate(datetime.datetime(2009, 5, 17, 12, 34, 56), DAY)"
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
SELECT
toMonday(parseDateTimeBestEffort('2009-05-17T12:34:56')) AS "TimestampTruncate(datetime.datetime(2009, 5, 17, 12, 34, 56), WEEK)"
CAST(toMonday(parseDateTimeBestEffort('2009-05-17T12:34:56')) AS Nullable(DateTime)) AS "TimestampTruncate(datetime.datetime(2009, 5, 17, 12, 34, 56), WEEK)"
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
SELECT
toStartOfYear(parseDateTimeBestEffort('2009-05-17T12:34:56')) AS "TimestampTruncate(datetime.datetime(2009, 5, 17, 12, 34, 56), YEAR)"
CAST(toStartOfYear(parseDateTimeBestEffort('2009-05-17T12:34:56')) AS Nullable(DateTime)) AS "TimestampTruncate(datetime.datetime(2009, 5, 17, 12, 34, 56), YEAR)"
16 changes: 16 additions & 0 deletions ibis/backends/clickhouse/tests/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,3 +492,19 @@ def my_eq(a: int, b: int) -> bool: ...
expr = alltypes.int_col.collect().filter(lambda x: my_eq(x, 1))
result = expr.execute()
assert set(result) == {1}


def test_timestamp_to_start_of_week(con):
pytest.importorskip("pyarrow")

expr = ibis.timestamp("2024-02-03 00:00:00").truncate("W")
result = con.to_pyarrow(expr).as_py()
assert result == datetime(2024, 1, 29, 0, 0, 0)


def test_date_to_start_of_day(con):
pytest.importorskip("pyarrow")

expr = ibis.date("2024-02-03")
expr1 = expr.truncate("D")
assert con.to_pyarrow(expr1) == con.to_pyarrow(expr)
26 changes: 20 additions & 6 deletions ibis/backends/sql/compilers/clickhouse.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,21 +377,35 @@ def visit_TimestampFromUNIX(self, op, *, arg, unit):

def visit_TimestampTruncate(self, op, *, arg, unit):
if (short := unit.short) == "W":
func = "toMonday"
funcname = "toMonday"
else:
func = f"toStartOf{unit.singular.capitalize()}"
funcname = f"toStartOf{unit.singular.capitalize()}"

if short in ("s", "ms", "us", "ns"):
arg = self.f.toDateTime64(arg, op.arg.dtype.scale or 0)
return self.f[func](arg)
func = self.f[funcname]

if short in ("Y", "Q", "M", "W", "D"):
# these units return `Date` so we have to cast back to the
# corresponding Ibis type
return self.cast(func(arg), op.dtype)
elif short in ("s", "ms", "us", "ns"):
return func(self.f.toDateTime64(arg, op.arg.dtype.scale or 0))
else:
assert short in ("h", "m"), short
return func(arg)

visit_TimeTruncate = visit_TimestampTruncate

def visit_DateTruncate(self, op, *, arg, unit):
if unit.short == "W":
if unit.short == "D":
# no op because truncating a date to a date has no effect
return arg
elif unit.short == "W":
func = "toMonday"
else:
func = f"toStartOf{unit.singular.capitalize()}"

# no cast needed here because all of the allowed units return `Date`
# values
return self.f[func](arg)

def visit_TimestampBucket(self, op, *, arg, interval, offset):
Expand Down

0 comments on commit 24e5395

Please sign in to comment.