Skip to content

Commit 03c1937

Browse files
committed
Fix decimal_to_nanoseconds for negative scales
1 parent 17ff223 commit 03c1937

File tree

1 file changed

+25
-5
lines changed

1 file changed

+25
-5
lines changed

datafusion/functions/src/datetime/to_timestamp.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -328,11 +328,12 @@ impl_to_timestamp_constructors!(ToTimestampMicrosFunc);
328328
impl_to_timestamp_constructors!(ToTimestampNanosFunc);
329329

330330
fn decimal_to_nanoseconds(value: i128, scale: i8) -> i64 {
331-
let scale_factor = 10_i128.pow(scale as u32);
332-
let seconds = value / scale_factor;
333-
let fraction = value % scale_factor;
334-
let nanos = (fraction * 1_000_000_000) / scale_factor;
335-
let timestamp_nanos = seconds * 1_000_000_000 + nanos;
331+
let nanos_exponent = 9_i16 - scale as i16;
332+
let timestamp_nanos = if nanos_exponent >= 0 {
333+
value * 10_i128.pow(nanos_exponent as u32)
334+
} else {
335+
value / 10_i128.pow(nanos_exponent.unsigned_abs() as u32)
336+
};
336337
timestamp_nanos as i64
337338
}
338339

@@ -1852,4 +1853,23 @@ mod tests {
18521853
assert_contains!(actual, expected);
18531854
}
18541855
}
1856+
1857+
#[test]
1858+
fn test_decimal_to_nanoseconds_negative_scale() {
1859+
// scale -2: internal value 5 represents 5 * 10^2 = 500 seconds
1860+
let nanos = decimal_to_nanoseconds(5, -2);
1861+
assert_eq!(nanos, 500_000_000_000); // 500 seconds in nanoseconds
1862+
1863+
// scale -1: internal value 10 represents 10 * 10^1 = 100 seconds
1864+
let nanos = decimal_to_nanoseconds(10, -1);
1865+
assert_eq!(nanos, 100_000_000_000);
1866+
1867+
// scale 0: internal value 5 represents 5 seconds
1868+
let nanos = decimal_to_nanoseconds(5, 0);
1869+
assert_eq!(nanos, 5_000_000_000);
1870+
1871+
// scale 3: internal value 1500 represents 1.5 seconds
1872+
let nanos = decimal_to_nanoseconds(1500, 3);
1873+
assert_eq!(nanos, 1_500_000_000);
1874+
}
18551875
}

0 commit comments

Comments
 (0)