Skip to content

Commit 169250f

Browse files
anjakefalacpcloud
authored andcommitted
feat(mysql): implement StringToTimestamp
Added test_string_to_timestamp for general backend.
1 parent 010abf1 commit 169250f

File tree

2 files changed

+84
-1
lines changed

2 files changed

+84
-1
lines changed

ibis/backends/mysql/registry.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,18 @@ def _timestamp_diff(t, expr):
112112
return sa.func.timestampdiff(sa.text('SECOND'), sa_right, sa_left)
113113

114114

115+
def _string_to_timestamp(t, expr):
116+
op = expr.op()
117+
sa_arg = t.translate(op.arg)
118+
sa_format_str = t.translate(op.format_str)
119+
if (op.timezone is not None) and op.timezone.op().value != "UTC":
120+
raise com.UnsupportedArgumentError(
121+
'MySQL backend only supports timezone UTC for converting'
122+
'string to timestamp.'
123+
)
124+
return sa.func.str_to_date(sa_arg, sa_format_str)
125+
126+
115127
def _literal(_, expr):
116128
if isinstance(expr, ir.IntervalScalar):
117129
if expr.type().unit in {'ms', 'ns'}:
@@ -190,6 +202,7 @@ def _find_in_set(t, expr):
190202
ops.TimestampAdd: fixed_arity(operator.add, 2),
191203
ops.TimestampSub: fixed_arity(operator.sub, 2),
192204
ops.TimestampDiff: _timestamp_diff,
205+
ops.StringToTimestamp: _string_to_timestamp,
193206
ops.DateTruncate: _truncate,
194207
ops.TimestampTruncate: _truncate,
195208
ops.IntervalFromInteger: _interval_from_integer,

ibis/backends/tests/test_temporal.py

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from pytest import param
1111

1212
import ibis
13+
import ibis.common.exceptions as com
1314
import ibis.expr.datatypes as dt
1415
from ibis.backends.pandas.execution.temporal import day_name
1516

@@ -563,7 +564,7 @@ def test_strftime(backend, alltypes, df, expr_fn, pandas_pattern):
563564
],
564565
)
565566
@pytest.mark.notimpl(["datafusion", "mysql", "postgres", "sqlite"])
566-
def test_to_timestamp(backend, con, unit):
567+
def test_integer_to_timestamp(backend, con, unit):
567568
backend_unit = backend.returned_timestamp_unit
568569
factor = unit_factors[unit]
569570

@@ -579,6 +580,75 @@ def test_to_timestamp(backend, con, unit):
579580
assert result == expected
580581

581582

583+
@pytest.mark.parametrize(
584+
'fmt, timezone',
585+
[
586+
# "11/01/10" - "month/day/year"
587+
param(
588+
'%m/%d/%y',
589+
"UTC",
590+
id="mysql_format",
591+
marks=pytest.mark.never(
592+
["pyspark"], reason="datetime formatting style not supported"
593+
),
594+
),
595+
param(
596+
'MM/dd/yy',
597+
"UTC",
598+
id="pyspark_format",
599+
marks=pytest.mark.never(
600+
["mysql"], reason="datetime formatting style not supported"
601+
),
602+
),
603+
],
604+
)
605+
@pytest.mark.notimpl(
606+
[
607+
'dask',
608+
'pandas',
609+
'postgres',
610+
'duckdb',
611+
'clickhouse',
612+
'sqlite',
613+
'impala',
614+
'datafusion',
615+
]
616+
)
617+
def test_string_to_timestamp(backend, con, fmt, timezone):
618+
table = con.table('functional_alltypes')
619+
result = table.mutate(
620+
date=table.date_string_col.to_timestamp(fmt, timezone)
621+
).execute()
622+
623+
# TEST: do we get the same date out, that we put in?
624+
# format string assumes that we are using pandas' strftime
625+
for i, val in enumerate(result["date"]):
626+
assert val.strftime("%m/%d/%y") == result["date_string_col"][i]
627+
628+
629+
@pytest.mark.notimpl(
630+
[
631+
'dask',
632+
'pandas',
633+
'postgres',
634+
'duckdb',
635+
'clickhouse',
636+
'sqlite',
637+
'impala',
638+
'datafusion',
639+
]
640+
)
641+
def test_string_to_timestamp_tz_error(backend, con):
642+
table = con.table('functional_alltypes')
643+
644+
with pytest.raises(com.UnsupportedArgumentError):
645+
table.mutate(
646+
date=table.date_string_col.to_timestamp(
647+
"%m/%d/%y", 'non-utc-timezone'
648+
)
649+
).compile()
650+
651+
582652
@pytest.mark.parametrize(
583653
('date', 'expected_index', 'expected_day'),
584654
[

0 commit comments

Comments
 (0)