in cpp-ch/local-engine/Storages/Serializations/ExcelReadHelpers.cpp [70:211]
bool readDatetime64TextWithExcel(
DB::DateTime64 & datetime64,
UInt32 scale,
DB::ReadBuffer & buf,
const DateLUTImpl & time_zone,
const DB::FormatSettings::CSV & settings,
bool quote)
{
/// Support more format.
/// Only parser for below:
/// yyyy-MM-dd HH:mm:ss,SSS
/// yyyy-MM-dd'T'HH:mm:ss
/// yyyy-MM-dd'T'HH:mm:ss.SSS
/// yyyy-MM-dd'T'HH:mm:ss'Z'
/// yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
/// Other will fallback to ch read.
/// The whole value is in buffer.
///
auto quick_return
= [&time_zone, &scale, &datetime64](
UInt16 year, UInt8 month, UInt8 day, UInt8 hour, UInt8 minute, UInt8 second, DB::DateTime64::NativeType fractional) -> bool
{
if (!day)
day = 1;
if (!checkDate(year, month, day))
return false;
time_t datetime = time_zone.makeDateTime(year, month, day, hour, minute, second);
return DB::DecimalUtils::tryGetDecimalFromComponents<DB::DateTime64>(datetime, fractional, scale, datetime64);
};
UInt16 year = 0;
UInt8 month = 0;
UInt8 day = 0;
UInt8 hour = 0;
UInt8 minute = 0;
UInt8 second = 0;
DB::DateTime64::NativeType fractional = 0;
char year_digits[std::numeric_limits<UInt64>::digits10];
size_t num_year_digits = readDigits(year_digits, sizeof(year_digits), buf);
if (num_year_digits != 4) // yyyyMM
return false;
readDecimalNumber<4>(year, year_digits);
char delimiter_after_year = *buf.position();
++buf.position();
char month_digits[std::numeric_limits<UInt64>::digits10];
size_t num_month_digits = readDigits(month_digits, sizeof(month_digits), buf);
if (num_month_digits == 1)
readDecimalNumber<1>(month, month_digits);
else if (num_month_digits == 2)
readDecimalNumber<2>(month, month_digits);
else
return false;
if (*buf.position() != delimiter_after_year) // delimiter must same char
return false;
++buf.position();
char day_digits[std::numeric_limits<UInt64>::digits10];
size_t num_day_digits = readDigits(day_digits, sizeof(day_digits), buf);
if (num_day_digits == 1)
readDecimalNumber<1>(day, day_digits);
else if (num_day_digits == 2)
readDecimalNumber<2>(day, day_digits);
else
return false;
char delimiter_after_day = *buf.position();
if (delimiter_after_day == settings.delimiter)
return quick_return(year, month, day, hour, minute, second, fractional);
if (delimiter_after_day != ' ' && delimiter_after_day != '\'')
return false;
++buf.position();
/// 'T'
if (*buf.position() == 'T')
{
++buf.position();
if (delimiter_after_day != *buf.position())
return false;
++buf.position();
}
if (!readNumber<2>(buf, hour))
return false;
if (*buf.position() != ':')
return false;
++buf.position();
if (!readNumber<2>(buf, minute))
return false;
if (*buf.position() != ':')
return false;
++buf.position();
if (!readNumber<2>(buf, second))
return false;
/// .SSS'Z'
/// if not has quote, not allow ',' after 'ss'
bool allow_comma = (settings.delimiter == ',' && quote) || (!quote && settings.delimiter != ',');
if (!buf.eof() && (*buf.position() == '.' || (allow_comma && *buf.position() == ',')))
{
++buf.position();
/// Read digits, up to 'scale' positions.
for (size_t i = 0; i < scale; ++i)
{
if (!buf.eof() && isNumericASCII(*buf.position()))
{
fractional *= 10;
fractional += *buf.position() - '0';
++buf.position();
}
else
fractional *= 10;
}
}
if (!buf.eof() && buf.position() + 3 <= buf.buffer().end())
{
/// ignore 'Z'
if (buf.position()[0] == '\'' && buf.position()[1] == 'Z' && buf.position()[2] == '\'')
buf.position() = buf.position() + 3;
}
return quick_return(year, month, day, hour, minute, second, fractional);
}