use std::collections::HashMap;
use chrono::{DateTime, NaiveDate, NaiveDateTime, Timelike, Utc, Datelike};
use std::error::Error;
pub fn to_timestamp(date_str: &str) -> Result<i64, Box<dyn Error>> {
let parsed_date = NaiveDate::parse_from_str(date_str, "%Y-%m-%d")?;
let datetime = NaiveDateTime::new(parsed_date, chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap());
let unix_timestamp = datetime.and_utc().timestamp();
Ok(unix_timestamp)
}
pub fn to_date(unix_timestamp: i64) -> String {
let datetime = DateTime::from_timestamp(unix_timestamp, 0).unwrap();
let date = datetime.date_naive();
date.to_string()
}
pub fn to_datetime(date_str: &str) -> Result<NaiveDateTime, Box<dyn Error>> {
let parsed_date = NaiveDate::parse_from_str(date_str, "%Y-%m-%d")?;
let datetime = NaiveDateTime::new(parsed_date, chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap());
Ok(datetime)
}
pub fn time_to_maturity(timestamp: i64) -> f64 {
let current_date = chrono::Local::now().naive_local().date();
let maturity_date = DateTime::from_timestamp_millis( timestamp * 1000).unwrap().date_naive();
(maturity_date - current_date).num_days() as f64 / 30.44
}
pub fn round_datetime_to_day(datetime: DateTime<Utc>) -> NaiveDateTime {
datetime.with_hour(0).unwrap().with_minute(0).unwrap().with_second(0).unwrap().naive_local()
}
pub fn round_datetime_to_hour(datetime: DateTime<Utc>) -> NaiveDateTime {
datetime.with_minute(0).unwrap().with_second(0).unwrap().naive_local()
}
pub fn round_datetime_to_minute(datetime: DateTime<Utc>) -> NaiveDateTime {
datetime.with_second(0).unwrap().naive_local()
}
pub fn convert_to_quarter(dates: Vec<&str>) -> Vec<String> {
dates.into_iter().map(|date_str| {
let date = NaiveDate::parse_from_str(date_str, "%Y-%m-%d").unwrap();
let year = if date.month() == 1 { date.year() - 1 } else { date.year() };
let quarter = match date.month() {
3 | 4 => 1,
6 | 7 => 2,
9 | 10 => 3,
12 | 1 => 4,
_ => unreachable!(),
};
format!("{year}Q{quarter}")
}).collect()
}
pub fn convert_to_year(dates: Vec<&str>) -> Vec<String> {
dates.into_iter().map(|date_str| {
let date = NaiveDate::parse_from_str(date_str, "%Y-%m-%d").unwrap();
let year = if date.month() <= 4 { date.year() - 1 } else { date.year() };
year.to_string()
}).collect()
}
#[derive(Debug, Copy, Clone)]
pub struct IntervalDays {
pub average: f64,
pub mode: f64,
}
pub fn interval_days(timestamps: Vec<NaiveDateTime>) -> IntervalDays {
let mut intervals = Vec::new();
let mut total_seconds = 0.0;
for window in timestamps.windows(2) {
let duration = window[1] - window[0];
let diff_seconds = duration.num_seconds() as f64;
let days = diff_seconds / 86400.0;
intervals.push(days);
total_seconds += diff_seconds;
}
let avg = total_seconds / (intervals.len() as f64 * 86400.0);
let mut interval_counts = HashMap::new();
let mut max_count = 0;
let mut mode = 0.0;
for &interval in &intervals {
let key = (interval * 10000.0) as i64;
let count = interval_counts.entry(key).or_insert(0);
*count += 1;
if *count > max_count || (*count == max_count && key < (mode * 10000.0) as i64) {
max_count = *count;
mode = key as f64 / 10000.0;
}
}
IntervalDays {
average: avg,
mode,
}
}