fix DT64 reader

This commit is contained in:
zvonand 2022-05-31 18:15:51 +03:00
parent 30a7b07d97
commit 8e28ba2583

View File

@ -908,6 +908,8 @@ inline ReturnType readDateTimeTextImpl(DateTime64 & datetime64, UInt32 scale, Re
return ReturnType(false);
}
int negative_multiplier = 1;
DB::DecimalUtils::DecimalComponents<DateTime64> components{static_cast<DateTime64::NativeType>(whole), 0};
if (!buf.eof() && *buf.position() == '.')
@ -934,29 +936,17 @@ inline ReturnType readDateTimeTextImpl(DateTime64 & datetime64, UInt32 scale, Re
while (!buf.eof() && isNumericASCII(*buf.position()))
++buf.position();
/// Keep sign of fractional part the same with whole part if datetime64 is negative
/// Case1:
/// 1965-12-12 12:12:12.123
/// => whole = -127914468, fractional = 123(coefficient>0)
/// => new whole = -127914467, new fractional = 877(coefficient<0)
///
/// Case2:
/// 1969-12-31 23:59:59.123
/// => whole = -1, fractional = 123(coefficient>0)
/// => new whole = 0, new fractional = -877(coefficient>0)
/// Fractional part (subseconds) is treated as positive by users
/// (as DateTime64 itself is a positive, although underlying decimal is negative),
/// so it needs proper handling
if (components.whole < 0 && components.fractional != 0)
{
const auto scale_multiplier = DecimalUtils::scaleMultiplier<DateTime64::NativeType>(scale);
++components.whole;
if (components.whole)
components.fractional = scale_multiplier - components.fractional;
if (!components.whole)
{
/// whole keep the sign, fractional should be non-negative
components.fractional = scale_multiplier - components.fractional;
}
else
{
/// when whole is zero, fractional should keep the sign
components.fractional = components.fractional - scale_multiplier;
negative_multiplier = -1;
}
}
}
@ -969,7 +959,7 @@ inline ReturnType readDateTimeTextImpl(DateTime64 & datetime64, UInt32 scale, Re
components.whole = components.whole / common::exp10_i32(scale);
}
datetime64 = DecimalUtils::decimalFromComponents<DateTime64>(components, scale);
datetime64 = negative_multiplier * DecimalUtils::decimalFromComponents<DateTime64>(components, scale);
return ReturnType(true);
}