inline bool readDateTextWithExcel()

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;
}