in cpp-ch/local-engine/Storages/Serializations/ExcelReadHelpers.cpp [201:308]
inline bool readDateTextWithExcel(LocalDate & date, DB::ReadBuffer & buf, bool is_us_style)
{
if (buf.eof())
return false;
/// Support more format include MM/dd/yyyy, yyyyMM, yyyy-MM, yyyy/MM.
/// The whole value is in buffer.
/// The delimiters can be arbitrary characters, like YYYY!MM, but obviously not digits.
UInt16 year = 0;
UInt8 month = 0;
UInt8 day = 0;
char first_digits[std::numeric_limits<UInt64>::digits10];
size_t num_first_digits = readDigits(first_digits, sizeof(first_digits), buf);
if (num_first_digits == 8) // yyyyMMdd
{
readDecimalNumber<4>(year, first_digits);
readDecimalNumber<2>(month, first_digits + 4);
readDecimalNumber<2>(day, first_digits + 6);
}
else if (num_first_digits == 6) // yyyyMM
{
readDecimalNumber<4>(year, first_digits);
readDecimalNumber<2>(month, first_digits + 4);
}
else if (num_first_digits == 4) // yyyy-MM, yyyy/MM, yyyy.M, yyyyMMdd, yyyy.M.d
{
readDecimalNumber<4>(year, first_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);
/// incorrect: yyyy-MMM
if (num_month_digits == 1)
readDecimalNumber<1>(month, month_digits);
else if (num_month_digits == 2)
readDecimalNumber<2>(month, month_digits);
else
return false;
/// yyyy-MM-xx fallback to ch parser
if (!buf.eof() && *buf.position() == delimiter_after_year)
{
++buf.position();
char day_digits[std::numeric_limits<UInt64>::digits10];
size_t num_day_digits = readDigits(day_digits, sizeof(day_digits), buf);
/// incorrect: yyyy-MM-ddd
if (num_day_digits == 1)
readDecimalNumber<1>(day, day_digits);
else if (num_day_digits == 2)
readDecimalNumber<2>(day, day_digits);
else
return false;
}
}
else if (is_us_style)
{
/// MM/dd/yyyy, M.d.yyyy
if (num_first_digits != 1 && num_first_digits != 2)
return false;
/// MM/dd/yyyy: 01/01/2023 or 1/1/2023
if (num_first_digits == 1)
readDecimalNumber<1>(month, first_digits);
else
readDecimalNumber<2>(month, first_digits);
char delimiter_after_year = *buf.position();
++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;
// incorrect: MM/dd-yyyy, MM/dd
if (buf.eof() || delimiter_after_year != *buf.position())
return false;
++buf.position();
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)
return false;
readDecimalNumber<4>(year, year_digits);
}
else
return false;
if (!day)
day = 1;
date = LocalDate(year, month, day);
return true;
}