taler-rust

GNU Taler code in Rust. Largely core banking integrations.
Log | Files | Refs | Submodules | README | LICENSE

timestamp.rs (3451B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2024-2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 
     17 use std::{fmt::Display, ops::Add};
     18 
     19 use jiff::{Timestamp, civil::Time, tz::TimeZone};
     20 use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error, ser::SerializeStruct}; // codespell:ignore
     21 use serde_json::Value;
     22 
     23 /// <https://docs.taler.net/core/api-common.html#tsref-type-Timestamp>
     24 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
     25 pub enum TalerTimestamp {
     26     Never,
     27     Timestamp(Timestamp),
     28 }
     29 
     30 #[derive(Serialize, Deserialize)]
     31 struct TimestampImpl {
     32     t_s: Value,
     33 }
     34 
     35 impl<'de> Deserialize<'de> for TalerTimestamp {
     36     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     37     where
     38         D: Deserializer<'de>,
     39     {
     40         let tmp = TimestampImpl::deserialize(deserializer)?;
     41         match tmp.t_s {
     42             Value::Number(s) => {
     43                 if let Some(since_epoch_s) = s.as_i64() {
     44                     jiff::Timestamp::from_second(since_epoch_s)
     45                         .map(Self::Timestamp)
     46                         .map_err(Error::custom)
     47                 } else {
     48                     Err(Error::custom("Expected epoch time"))
     49                 }
     50             }
     51             Value::String(str) if str == "never" => Ok(Self::Never),
     52             _ => Err(Error::custom("Expected epoch time or 'never'")),
     53         }
     54     }
     55 }
     56 
     57 impl Serialize for TalerTimestamp {
     58     fn serialize<S>(&self, se: S) -> Result<S::Ok, S::Error>
     59     where
     60         S: Serializer,
     61     {
     62         let mut se_struct = se.serialize_struct("Timestamp", 1)?;
     63         match self {
     64             TalerTimestamp::Never => se_struct.serialize_field("t_s", "never")?,
     65             TalerTimestamp::Timestamp(timestamp) => {
     66                 se_struct.serialize_field("t_s", &timestamp.as_second())?
     67             }
     68         }
     69         se_struct.end()
     70     }
     71 }
     72 
     73 impl Display for TalerTimestamp {
     74     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     75         match self {
     76             TalerTimestamp::Never => f.write_str("never"),
     77             TalerTimestamp::Timestamp(timestamp) => timestamp.fmt(f),
     78         }
     79     }
     80 }
     81 
     82 impl From<jiff::Timestamp> for TalerTimestamp {
     83     fn from(time: jiff::Timestamp) -> Self {
     84         Self::Timestamp(time)
     85     }
     86 }
     87 
     88 impl From<jiff::civil::Date> for TalerTimestamp {
     89     fn from(date: jiff::civil::Date) -> Self {
     90         date.to_datetime(Time::midnight())
     91             .to_zoned(TimeZone::UTC)
     92             .unwrap()
     93             .timestamp()
     94             .into()
     95     }
     96 }
     97 
     98 impl Add<jiff::Span> for TalerTimestamp {
     99     type Output = Self;
    100 
    101     fn add(self, rhs: jiff::Span) -> Self::Output {
    102         match self {
    103             TalerTimestamp::Never => TalerTimestamp::Never,
    104             TalerTimestamp::Timestamp(timestamp) => TalerTimestamp::Timestamp(timestamp + rhs),
    105         }
    106     }
    107 }