Skip to content

Non-constant DATE_TRUNC expression regression for values before epoch #18334

Closed

Description

@sadboy

Describe the bug

On DF 50, DATE_TRUNC function sometimes returns off-by-1 result.

To Reproduce

DataFusion CLI v50.3.0
> select d as datetime,
DATE_TRUNC('hour', d) as hour_from_column,
DATE_TRUNC('hour', (timestamp '1900-06-15 07:09:00')) as hour_from_const
from (values (timestamp '1900-06-15 07:09:00')) as T(d);
+---------------------+---------------------+---------------------+
| datetime            | hour_from_column    | hour_from_const     |
+---------------------+---------------------+---------------------+
| 1900-06-15T07:09:00 | 1900-06-15T08:00:00 | 1900-06-15T07:00:00 |
+---------------------+---------------------+---------------------+
1 row(s) fetched. 
Elapsed 0.006 seconds.

Expected behavior

hour_from_column should have the same value as hour_from_const

Additional context

No response

Activity

  1. added theissue type on Oct 28, 2025
  2. sadboy commented on Oct 28, 2025

    @sadboy
    ContributorAuthor

    Also exists on main as of commit e9431fc

  3. sadboy commented on Oct 28, 2025

    @sadboy
    ContributorAuthor

    Caused by #16859 -- removing

    if matches!(
    granularity.as_str(),
    // For modern timezones, it's correct to truncate "minute" in this way.
    // Both datafusion and arrow are ignoring historical timezone's non-minute granularity
    // bias (e.g., Asia/Kathmandu before 1919 is UTC+05:41:16).
    "second" | "minute" | "millisecond" | "microsecond"
    ) ||
    // In UTC, "hour" and "day" have uniform durations and can be truncated with simple arithmetic
    (parsed_tz.is_none() && matches!(granularity.as_str(), "hour" | "day"))
    {
    let result = general_date_trunc_array_fine_granularity(
    T::UNIT,
    array,
    granularity.as_str(),
    )?;
    return Ok(ColumnarValue::Array(result));
    }
    let array: PrimitiveArray<T> = array
    .try_unary(|x| {
    general_date_trunc(T::UNIT, x, parsed_tz, granularity.as_str())
    })?
    .with_timezone_opt(tz_opt.clone());
    Ok(ColumnarValue::Array(Arc::new(array)))
    }
    appears to fix the problem

    cc @waynexia @findepi

  4. comphead commented on Oct 28, 2025

    @comphead
    Contributor

    Thanks @sadboy appreciate if you also add a regression test

  5. alamb commented on Oct 29, 2025

    @alamb
    Contributor
  6. changed the title [-]Non-constant `DATE_TRUNC` expression regression[/-] [+]Non-constant `DATE_TRUNC` expression regression for values before epoch[/+] on Oct 29, 2025
  7. added a commit that references this issue on Oct 30, 2025
    52894db
  8. added a commit that references this issue on Nov 2, 2025
    72db2e2
  9. added a commit that references this issue on Nov 11, 2025
    7a00227
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingregressionSomething that used to work no longer does

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions