Skip to content

Instantly share code, notes, and snippets.

@rust-play
Created July 22, 2024 18:04
Show Gist options
  • Save rust-play/10490724df1a9b9976125ccecd12ac3e to your computer and use it in GitHub Desktop.
Save rust-play/10490724df1a9b9976125ccecd12ac3e to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
use std::str::FromStr;
use std::fmt::Display;
use chrono::{DateTime, TimeZone, Offset, Utc, Datelike};
use chrono_tz::Tz;
use serde::{Serialize, Deserialize};
use serde_with::{serde_as, TryFromInto};
trait TzName: TimeZone {
fn tz_name(&self) -> &'static str;
}
trait TzFromName: TimeZone {
type Error: Display;
fn tz_from_name(name: &str) -> Result<Self, Self::Error>;
}
impl TzName for Tz {
fn tz_name(&self) -> &'static str {
self.name()
}
}
impl TzFromName for Tz {
type Error = &'static str; // demo
fn tz_from_name(name: &str) -> Result<Self, Self::Error> {
Tz::from_str(name).map_err(|_| "")
}
}
// Could add impls for tzfile too, but I don't think it exposes the name
#[derive(Debug, Clone, Serialize, Deserialize)]
struct ZonedDt {
tp_secs: i64,
tp_nsecs: u32,
tz_name: Box<str>,
local_minus_utc: i32,
}
impl<Z: TzName> From<DateTime<Z>> for ZonedDt {
fn from(value: DateTime<Z>) -> Self {
let tp_secs = value.timestamp();
let tp_nsecs = value.timestamp_subsec_nanos();
let tz = value.timezone();
let tz_name = tz.tz_name().into();
let local_minus_utc = tz.offset_from_utc_datetime(&value.naive_utc()).fix().local_minus_utc();
Self { tp_secs, tp_nsecs, tz_name, local_minus_utc }
}
}
impl<Z: TzFromName> TryFrom<ZonedDt> for DateTime<Z> {
type Error = &'static str; // demo code
fn try_from(value: ZonedDt) -> Result<Self, Self::Error> {
let tz_from_name = Z::tz_from_name(&*value.tz_name).map_err(|_| "")?;
let utc_dt = <DateTime<Utc>>::from_timestamp(value.tp_secs, value.tp_nsecs)
.ok_or_else(|| "")?;
let naive_utc_dt = utc_dt.naive_utc();
let tz_fixed_offset = tz_from_name.offset_from_utc_datetime(&naive_utc_dt).fix();
if tz_fixed_offset.local_minus_utc() != value.local_minus_utc {
return Err("");
} else {
Ok(tz_from_name.from_utc_datetime(&naive_utc_dt))
}
}
}
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
struct HasZDT {
#[serde_as(as = "TryFromInto<ZonedDt>")]
zdt: DateTime<Tz>,
}
fn main() {
let tz = Tz::from_str("Europe/Kyiv").unwrap();
let mut zdt = tz.from_utc_datetime(&Utc::now().naive_utc());
zdt = zdt.with_year(zdt.year() + 1).unwrap();
let v = HasZDT{ zdt };
let json = serde_json::to_string(&v).unwrap();
eprintln!("JSON={json}");
let v_from_json = serde_json::from_str::<HasZDT>(&json).unwrap();
eprintln!("deserialized zdt={}", v_from_json.zdt);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment