databendlabs/databend · info

midnight is valid

Error message

midnight is valid

What it means

string_to_timestamp_tz parses timestamp text; when the text is a bare date (YYYY-MM-DD), it treats it as midnight in the session timezone via date.and_hms_opt(0,0,0). The expect('midnight is valid') fires only if chrono cannot construct midnight on the parsed date — impossible for any NaiveDate that successfully parsed from %Y-%m-%d, making it an invariant assertion rather than an input check.

Solutions

  1. No caller action needed; input issues surface as ErrorCode::BadBytes or the check_input_year error instead.
  2. Keep the format constant '%Y-%m-%d' in sync with and_hms_opt usage if refactoring.
Defensive patterns

Strategy: validation

Validate before calling

// Not required; bare-date inputs return proper errors for bad UTF-8/year.
let ts = string_to_timestamp_tz(text, &tz)?;

Prevention

When it happens

Trigger: Effectively never: any NaiveDate parseable from '%Y-%m-%d' supports 00:00:00. Could only fire on chrono regression or if the parsing path is changed to allow out-of-range hour components.

Common situations: Not user-reachable; encountered only when modifying the parse formats or chrono versions.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/3678db255fd30329. Report an issue: GitHub.

Appendix: source

Thrown at src/query/expression/src/types/timestamp_tz.rs:267

    build_timestamp_tz(micros, resolved.offset_seconds)
}

#[inline]
pub fn string_to_timestamp_tz<'a, F: FnOnce() -> &'a Tz>(
    ts_str: &[u8],
    fn_tz: F,
) -> databend_common_exception::Result<timestamp_tz> {
    if let Some(parsed) = try_parse_standard_timestamp_with_offset(ts_str) {
        return parsed;
    }

    let text = std::str::from_utf8(ts_str)
        .map_err(|_| ErrorCode::BadBytes("Timestamp text is not valid UTF-8".to_string()))?
        .trim();

    // A bare date is midnight in the session timezone.
    if let Ok(date) = NaiveDate::parse_from_str(text, "%Y-%m-%d") {
        let local = date.and_hms_opt(0, 0, 0).expect("midnight is valid");
        return timestamp_tz_from_local(&local, fn_tz());
    }

    for format in PARSE_FORMATS_WITH_OFFSET {
        if let Ok(value) = DateTime::parse_from_str(text, format) {
            check_input_year(value.year())?;
            check_timezone_offset(value.offset().local_minus_utc())?;
            let micros = i128::from(value.timestamp()) * 1_000_000
                + i128::from(value.timestamp_subsec_micros());
            return build_timestamp_tz(micros, value.offset().local_minus_utc());
        }
    }

    for format in PARSE_FORMATS_NAIVE {
        if let Ok(local) = NaiveDateTime::parse_from_str(text, format) {
            return timestamp_tz_from_local(&local, fn_tz());
        }
    }

View on GitHub (pinned to 288d84d76e)