1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
use std::ops::Bound;

use exc_core::ExchangeError;
use time::OffsetDateTime;

mod book;
mod candle;
mod instrument;
mod trade;
mod trading;
mod utils;

pub(crate) fn from_timestamp(ts: i64) -> Result<OffsetDateTime, ExchangeError> {
    OffsetDateTime::from_unix_timestamp_nanos((ts as i128) * 1_000_000)
        .map_err(|err| ExchangeError::Other(anyhow!("parse timestamp error: {err}")))
}

pub(crate) fn to_timestamp(ts: &OffsetDateTime) -> Result<i64, ExchangeError> {
    let ts = ts.unix_timestamp_nanos() / 1_000_000;
    if ts > (i64::MAX as i128) {
        return Err(ExchangeError::Other(anyhow!("datetime too big: {ts}")));
    }
    Ok(ts as i64)
}

pub(crate) fn start_bound_to_timestamp(
    start: Bound<&OffsetDateTime>,
) -> Result<Option<i64>, ExchangeError> {
    match start {
        Bound::Included(ts) => Ok(Some(to_timestamp(ts)?)),
        Bound::Excluded(ts) => Ok(Some(to_timestamp(&(*ts + time::Duration::SECOND))?)),
        Bound::Unbounded => Ok(None),
    }
}

pub(crate) fn end_bound_to_timestamp(
    end: Bound<&OffsetDateTime>,
) -> Result<Option<i64>, ExchangeError> {
    match end {
        Bound::Included(ts) => Ok(Some(to_timestamp(ts)?)),
        Bound::Excluded(ts) => Ok(Some(to_timestamp(&(*ts - time::Duration::SECOND))?)),
        Bound::Unbounded => Ok(None),
    }
}