use chrono::{DateTime, Duration, TimeZone, Utc};
use std::sync::{Arc, RwLock};
pub trait TimeProvider: Send + Sync + std::fmt::Debug {
fn current_time(&self) -> DateTime<Utc>;
}
#[derive(Debug)]
pub struct SystemTimeProvider;
impl TimeProvider for SystemTimeProvider {
fn current_time(&self) -> DateTime<Utc> {
Utc::now()
}
}
#[derive(Debug, Clone)]
pub struct MockTimeProvider {
time: Arc<RwLock<DateTime<Utc>>>,
}
impl Default for MockTimeProvider {
fn default() -> Self {
Self::new(Utc.timestamp(0, 0))
}
}
impl MockTimeProvider {
pub fn new(time: DateTime<Utc>) -> Self {
Self {
time: Arc::new(RwLock::new(time)),
}
}
pub fn time(&self) -> DateTime<Utc> {
*self.time.read().unwrap()
}
pub fn set_time(&self, new_time: DateTime<Utc>) {
let mut time = self.time.write().unwrap();
*time = new_time;
}
pub fn add_time(&self, duration: Duration) {
let mut time = self.time.write().unwrap();
*time = *time + duration;
}
}
impl TimeProvider for MockTimeProvider {
fn current_time(&self) -> DateTime<Utc> {
self.time()
}
}
#[allow(clippy::use_self)] impl From<MockTimeProvider> for Arc<dyn TimeProvider> {
fn from(time_provider: MockTimeProvider) -> Self {
Arc::new(time_provider)
}
}
#[allow(clippy::use_self)] impl From<SystemTimeProvider> for Arc<dyn TimeProvider> {
fn from(time_provider: SystemTimeProvider) -> Self {
Arc::new(time_provider)
}
}