flowsurface_data/config/
timezone.rs1use std::fmt;
2
3use chrono::DateTime;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Copy, PartialEq, Default)]
7pub enum UserTimezone {
8 #[default]
9 Utc,
10 Local,
11}
12
13impl UserTimezone {
14 pub fn format_timestamp(&self, timestamp: i64, timeframe: exchange::Timeframe) -> String {
16 if let Some(datetime) = DateTime::from_timestamp(timestamp, 0) {
17 match self {
18 UserTimezone::Local => {
19 let time_with_zone = datetime.with_timezone(&chrono::Local);
20 Self::format_by_timeframe(&time_with_zone, timeframe)
21 }
22 UserTimezone::Utc => {
23 let time_with_zone = datetime.with_timezone(&chrono::Utc);
24 Self::format_by_timeframe(&time_with_zone, timeframe)
25 }
26 }
27 } else {
28 String::new()
29 }
30 }
31
32 fn format_by_timeframe<Tz: chrono::TimeZone>(
34 datetime: &DateTime<Tz>,
35 timeframe: exchange::Timeframe,
36 ) -> String
37 where
38 Tz::Offset: std::fmt::Display,
39 {
40 let interval = timeframe.to_milliseconds();
41
42 if interval < 10000 {
43 datetime.format("%M:%S").to_string()
44 } else if datetime.format("%H:%M").to_string() == "00:00" {
45 datetime.format("%-d").to_string()
46 } else {
47 datetime.format("%H:%M").to_string()
48 }
49 }
50
51 pub fn format_crosshair_timestamp(&self, timestamp_millis: i64, interval: u64) -> String {
53 if let Some(datetime) = DateTime::from_timestamp_millis(timestamp_millis) {
54 if interval < 10000 {
55 return datetime.format("%M:%S.%3f").to_string();
56 }
57
58 match self {
59 UserTimezone::Local => datetime
60 .with_timezone(&chrono::Local)
61 .format("%a %b %-d %H:%M")
62 .to_string(),
63 UserTimezone::Utc => datetime
64 .with_timezone(&chrono::Utc)
65 .format("%a %b %-d %H:%M")
66 .to_string(),
67 }
68 } else {
69 String::new()
70 }
71 }
72}
73
74impl fmt::Display for UserTimezone {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 match self {
77 UserTimezone::Utc => write!(f, "UTC"),
78 UserTimezone::Local => {
79 let local_offset = chrono::Local::now().offset().local_minus_utc();
80 let hours = local_offset / 3600;
81 let minutes = (local_offset % 3600) / 60;
82 write!(f, "Local (UTC {hours:+03}:{minutes:02})")
83 }
84 }
85 }
86}
87
88impl<'de> Deserialize<'de> for UserTimezone {
89 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
90 where
91 D: serde::Deserializer<'de>,
92 {
93 let timezone_str = String::deserialize(deserializer)?;
94 match timezone_str.to_lowercase().as_str() {
95 "utc" => Ok(UserTimezone::Utc),
96 "local" => Ok(UserTimezone::Local),
97 _ => Err(serde::de::Error::custom("Invalid UserTimezone")),
98 }
99 }
100}
101
102impl Serialize for UserTimezone {
103 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104 where
105 S: serde::Serializer,
106 {
107 match self {
108 UserTimezone::Utc => serializer.serialize_str("UTC"),
109 UserTimezone::Local => serializer.serialize_str("Local"),
110 }
111 }
112}