use crate::error::Error;
use crate::qconsts::qnull_base;
use crate::qnull_inf::{qinf, qninf, qnull};
use crate::types::Result;
use chrono::prelude::*;
use chrono::Duration;
pub const ONE_DAY_NANOS: i64 = 86400000000000;
pub const ONE_DAY_MILLIS: i64 = 86400000;
pub const KDB_MONTH_OFFSET: i32 = 360;
pub const KDB_DAY_OFFSET: i32 = 10957;
pub const KDB_TIMESTAMP_OFFSET: i64 = 946684800000000000;
pub fn q_timestamp_to_datetime(nanos: i64) -> DateTime<Utc> {
Utc.timestamp_nanos(nanos) + Duration::nanoseconds(KDB_TIMESTAMP_OFFSET)
}
pub fn q_month_to_date(months: i32) -> NaiveDate {
if months == qnull_base::I {
qnull::MONTH
} else if months <= -3171072 {
*qninf::MONTH
} else if months >= 3121728 {
*qinf::MONTH
} else {
NaiveDate::from_ymd_opt(2000 + months / 12, 1 + (months % 12) as u32, 1).unwrap()
}
}
pub fn q_date_to_date(days: i32) -> Result<NaiveDate> {
if days == qnull_base::I {
Ok(qnull::DATE)
} else if days <= -96476615 {
Ok(*qninf::DATE)
} else if days >= 95015644 {
Ok(qinf::DATE)
} else {
Ok((NaiveDate::from_ymd_opt(2000, 1, 1)
.ok_or_else(|| Error::InvalidDateTime)?
.and_hms_opt(0, 0, 0)
.ok_or_else(|| Error::InvalidDateTime)?
.and_local_timezone(Utc)
.unwrap()
+ Duration::days(days as i64))
.date_naive())
}
}
pub fn q_datetime_to_datetime(days: f64) -> DateTime<Utc> {
if days.is_nan() {
qnull::DATETIME
} else if days <= -96476615 as f64 {
*qninf::DATETIME
} else if days >= 95015644 as f64 {
*qinf::DATETIME
} else {
Utc.timestamp_millis_opt((ONE_DAY_MILLIS as f64 * (days + KDB_DAY_OFFSET as f64)) as i64)
.unwrap()
}
}
pub fn q_timespan_to_duration(nanos: i64) -> Duration {
Duration::nanoseconds(nanos)
}
pub fn q_minute_to_duration(minutes: i32) -> Duration {
Duration::minutes(minutes as i64)
}
pub fn q_second_to_duration(seconds: i32) -> Duration {
Duration::seconds(seconds as i64)
}
pub fn q_time_to_duration(millis: i32) -> Duration {
Duration::milliseconds(millis as i64)
}