bool readDatetime64TextWithExcel()

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