**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

const bool right_is_string = isStringOrFixedString(which_right);
        bool date_and_datetime = (which_left.idx != which_right.idx) &&
            which_left.isDateOrDateTime() && which_right.isDateOrDateTime();
        ColumnPtr res;
        if (left_is_num && right_is_num && !date_and_datetime)
        {
            if (!((res = executeNumLeftType<UInt8>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<UInt16>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<UInt32>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<UInt64>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<UInt128>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<UInt256>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<Int8>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<Int16>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<Int32>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<Int64>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<Int128>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<Int256>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<Float32>(col_left_untyped, col_right_untyped))
                || (res = executeNumLeftType<Float64>(col_left_untyped, col_right_untyped))))
                throw Exception("Illegal column " + col_left_untyped->getName()
                    + " of first argument of function " + getName(),
                    ErrorCodes::ILLEGAL_COLUMN);
            return res;
        }
        else if (checkAndGetDataType<DataTypeTuple>(left_type.get())
            && checkAndGetDataType<DataTypeTuple>(right_type.get()))
        {
            return executeTuple(result_type, col_with_type_and_name_left, col_with_type_and_name_right, input_rows_count);
        }