**Use case**

Comparison between DateTime64 and DateTime / Date types is allowed but the behavior is confusing (it looks like used numerical comparison):

* from one side for zero-precision it works as expected (values compared as datetime-based ones): 

```sql
SELECT toTypeName(dt64) AS dt64_typename, dt64 = dt
FROM 
(
    SELECT 
        toDateTime64(toStartOfInterval(now(), toIntervalSecond(1), 'UTC'), 0, 'UTC') AS dt64,
        toStartOfInterval(now(), toIntervalSecond(1), 'UTC') AS dt
)

/*
┌─dt64_typename────────┬─equals(dt64, dt)─┐
│ DateTime64(0, 'UTC') │                1 │
└──────────────────────┴──────────────────┘
*/
```
* from another side for non-zero-precision its behavior is unexpected if not used explicit type conversion:

```sql
SELECT 
    toTypeName(dt64) AS dt64_typename,
    dt64 = dt,
    toDateTime(dt64) = dt,
    dt64 = toDateTime64(dt, 1, 'UTC')
FROM 
(
    SELECT 
        toDateTime64(toStartOfInterval(now(), toIntervalSecond(1), 'UTC'), 1, 'UTC') AS dt64,
        toStartOfInterval(now(), toIntervalSecond(1), 'UTC') AS dt
)
/*
┌─dt64_typename────────┬─equals(dt64, dt)─┬─equals(toDateTime(dt64), dt)─┬─equals(dt64, toDateTime64(dt, 1, 'UTC'))─┐
│ DateTime64(1, 'UTC') │                0 │                            1 │                                        1 │
└──────────────────────┴──────────────────┴──────────────────────────────┴──────────────────────────────────────────┘
*/
```

**Describe the solution you'd like**
I think this comparison either:
- should be not allowed and throw an exception to ask for user uses explicit conversion
- or make valid implicit conversion relying on datetime/date essence of values

throw Exception("Cannot compare tuples of different sizes.", ErrorCodes::BAD_ARGUMENTS);
        if (result_type->onlyNull())
            return result_type->createColumnConstWithDefaultValue(input_rows_count);
        ColumnsWithTypeAndName x(tuple_size);
        ColumnsWithTypeAndName y(tuple_size);
        const auto * x_const = checkAndGetColumnConst<ColumnTuple>(c0.column.get());
        const auto * y_const = checkAndGetColumnConst<ColumnTuple>(c1.column.get());
        Columns x_columns;
        Columns y_columns;
        if (x_const)
            x_columns = convertConstTupleToConstantElements(*x_const);
        else
            x_columns = assert_cast<const ColumnTuple &>(*c0.column).getColumnsCopy();
        if (y_const)
            y_columns = convertConstTupleToConstantElements(*y_const);
        else
            y_columns = assert_cast<const ColumnTuple &>(*c1.column).getColumnsCopy();
        for (size_t i = 0; i < tuple_size; ++i)
        {
            x[i].type = static_cast<const DataTypeTuple &>(*c0.type).getElements()[i];
            y[i].type = static_cast<const DataTypeTuple &>(*c1.type).getElements()[i];
            x[i].column = x_columns[i];
            y[i].column = y_columns[i];
        }
        return executeTupleImpl(x, y, tuple_size, input_rows_count);
    }
    ColumnPtr executeTupleImpl(const ColumnsWithTypeAndName & x,
                          const ColumnsWithTypeAndName & y, size_t tuple_size,
                          size_t input_rows_count) const;
    ColumnPtr executeTupleEqualityImpl(