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", ×tamp.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 }