diff --git a/ibis/expr/api.py b/ibis/expr/api.py index ffe3192305273..40245d6d79d2c 100644 --- a/ibis/expr/api.py +++ b/ibis/expr/api.py @@ -59,7 +59,8 @@ __all__ = [ - 'schema', 'table', 'literal', 'expr_list', 'timestamp', + 'schema', 'table', 'literal', 'expr_list', + 'timestamp', 'time', 'case', 'where', 'sequence', 'now', 'desc', 'null', 'NA', 'cast', 'coalesce', 'greatest', 'least', @@ -174,6 +175,24 @@ def timestamp(value): return ir.TimestampScalar(ir.literal(value).op()) +def time(value): + """ + Returns a time literal if value is likely coercible to a time + + Parameters + ---------- + value : time value as string + + Returns + -------- + result : TimeScalar + """ + if isinstance(value, six.string_types): + from pandas.core.tools.datetimes import to_time + value = to_time(value) + return ir.TimeScalar(ir.literal(value).op()) + + schema.__doc__ = """\ Validate and return an Ibis Schema object diff --git a/ibis/expr/tests/test_value_exprs.py b/ibis/expr/tests/test_value_exprs.py index 149ebdb8b26c0..40d926447a59e 100644 --- a/ibis/expr/tests/test_value_exprs.py +++ b/ibis/expr/tests/test_value_exprs.py @@ -13,7 +13,7 @@ # limitations under the License. import operator -from datetime import date, datetime +from datetime import date, datetime, time import pytest @@ -905,3 +905,53 @@ def test_decimal_modulo_output_type(value, type, expected_type_class): t = ibis.table([('a', type)]) expr = t.a % value assert isinstance(expr.type(), expected_type_class) + + +@pytest.mark.parametrize( + ('left', 'right'), + [ + (literal('10:00'), time(10, 0)), + (time(10, 0), literal('10:00')), + ] +) +@pytest.mark.parametrize( + 'op', + [ + operator.eq, + operator.ne, + operator.lt, + operator.le, + operator.gt, + operator.ge, + lambda left, right: ibis.time( + '10:00' + ).between(left, right), + ] +) +def test_time_compare(op, left, right): + result = op(left, right) + assert result.type().equals(dt.boolean) + + +@pytest.mark.parametrize( + ('left', 'right'), + [ + (literal('10:00'), date(2017, 4, 2)), + (literal('10:00'), datetime(2017, 4, 2, 1, 1)), + (literal('10:00'), literal('2017-04-01')), + (time(10, 0), literal('2017-04-01')), + ] +) +@pytest.mark.parametrize( + 'op', + [ + operator.eq, + operator.lt, + operator.le, + operator.gt, + operator.ge, + ] +) +def test_time_timestamp_invalid_compare(op, left, right): + result = op(left, right) + assert result.type().equals(dt.boolean) diff --git a/ibis/expr/types.py b/ibis/expr/types.py index 579761213b211..4e5ade4bd003f 100644 --- a/ibis/expr/types.py +++ b/ibis/expr/types.py @@ -536,6 +536,8 @@ def infer_literal_type(value): return dt.timestamp elif isinstance(value, datetime.date): return dt.date + elif isinstance(value, datetime.time): + return dt.time elif isinstance(value, list): return dt.Array(rules.highest_precedence_type( list(map(literal, value))