Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/query/expression/src/types/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use databend_common_column::buffer::Buffer;
use databend_common_exception::ErrorCode;
use databend_common_io::cursor_ext::BufferReadDateTimeExt;
use databend_common_io::cursor_ext::ReadBytesExt;
use jiff::SignedDuration;
use jiff::civil::Date;
use jiff::fmt::strtime;
use jiff::tz::TimeZone;
Expand All @@ -32,7 +33,6 @@ use super::SimpleValueType;
use super::number::SimpleDomain;
use crate::ColumnBuilder;
use crate::ScalarRef;
use crate::date_helper::DateConverter;
use crate::property::Domain;
use crate::values::Column;
use crate::values::Scalar;
Expand All @@ -45,6 +45,11 @@ pub const DATE_MIN: i32 = -719162;
/// 9999-12-31
pub const DATE_MAX: i32 = 2932896;

pub fn date_from_days(days: impl AsPrimitive<i64>) -> Date {
let duration = SignedDuration::from_hours(days.as_() * 24);
Date::constant(1970, 1, 1).checked_add(duration).unwrap()
}

/// Check if date is within range.
/// /// If days is invalid convert to DATE_MIN.
#[inline]
Expand Down Expand Up @@ -161,7 +166,6 @@ pub fn string_to_date(
}

#[inline]
pub fn date_to_string(date: impl AsPrimitive<i64>, tz: &TimeZone) -> impl Display {
let res = date.as_().to_date(tz);
strtime::format(DATE_FORMAT, res).unwrap()
pub fn date_to_string(date: impl AsPrimitive<i64>) -> String {
strtime::format(DATE_FORMAT, date_from_days(date)).unwrap()
}
31 changes: 29 additions & 2 deletions src/query/expression/src/types/timestamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ use databend_common_exception::ErrorCode;
use databend_common_io::cursor_ext::BufferReadDateTimeExt;
use databend_common_io::cursor_ext::DateTimeResType;
use databend_common_io::cursor_ext::ReadBytesExt;
use jiff::Timestamp;
use jiff::Zoned;
use jiff::fmt::strtime;
use jiff::tz::TimeZone;
use num_traits::AsPrimitive;

use super::ArgType;
use super::DataType;
Expand All @@ -33,7 +35,6 @@ use super::number::SimpleDomain;
use crate::ColumnBuilder;
use crate::ScalarRef;
use crate::property::Domain;
use crate::utils::date_helper::DateConverter;
use crate::values::Column;
use crate::values::Scalar;

Expand All @@ -46,6 +47,32 @@ pub const TIMESTAMP_MAX: i64 = 253402300799999999;
pub const MICROS_PER_SEC: i64 = 1_000_000;
pub const MICROS_PER_MILLI: i64 = 1_000;

// jiff's `Timestamp` only accepts UTC seconds in
// [-377705023201, 253402207200] so that any +/-25:59:59 offset still
// yields a valid civil datetime. Clamp after splitting into seconds
// and sub-second nanoseconds to avoid constructing out-of-range values.
const JIFF_TIMESTAMP_MIN_SEC: i64 = -377705023201;
const JIFF_TIMESTAMP_MAX_SEC: i64 = 253402207200;

pub fn timestamp_from_micros(micros: impl AsPrimitive<i64>, tz: &TimeZone) -> Zoned {
// Can't use `tz.timestamp_nanos(micros.as_() * 1000)` directly, as it may overflow.
let micros = micros.as_();
let (mut secs, mut nanos) = (micros / MICROS_PER_SEC, (micros % MICROS_PER_SEC) * 1_000);
if nanos < 0 {
secs -= 1;
nanos += 1_000_000_000;
}
if secs > JIFF_TIMESTAMP_MAX_SEC {
secs = JIFF_TIMESTAMP_MAX_SEC;
nanos = 0;
} else if secs < JIFF_TIMESTAMP_MIN_SEC {
secs = JIFF_TIMESTAMP_MIN_SEC;
nanos = 0;
}
let ts = Timestamp::new(secs, nanos as i32).unwrap();
ts.to_zoned(tz.clone())
}

pub const PRECISION_MICRO: u8 = 6;
pub const PRECISION_MILLI: u8 = 3;
pub const PRECISION_SEC: u8 = 0;
Expand Down Expand Up @@ -194,6 +221,6 @@ pub fn string_to_timestamp(

#[inline]
pub fn timestamp_to_string(ts: i64, tz: &TimeZone) -> impl Display {
let zdt = ts.to_timestamp(tz);
let zdt = timestamp_from_micros(ts, tz);
strtime::format(TIMESTAMP_FORMAT, &zdt).unwrap()
}
2 changes: 1 addition & 1 deletion src/query/expression/src/types/variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ pub fn cast_scalar_to_variant(
ScalarRef::Decimal(v) => v.to_string(),
ScalarRef::Boolean(v) => v.to_string(),
ScalarRef::Timestamp(v) => timestamp_to_string(v, tz).to_string(),
ScalarRef::Date(v) => date_to_string(v, tz).to_string(),
ScalarRef::Date(v) => date_to_string(v),
_ => unreachable!(),
};
let mut val = vec![];
Expand Down
Loading