-
-
Save rust-play/10490724df1a9b9976125ccecd12ac3e to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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