You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by ti...@apache.org on 2025/10/02 15:39:44 UTC

(opendal-reqsign) branch major-version updated: wrap jiff Timestamp

This is an automated email from the ASF dual-hosted git repository.

tison pushed a commit to branch major-version
in repository https://gitbox.apache.org/repos/asf/opendal-reqsign.git


The following commit(s) were added to refs/heads/major-version by this push:
     new 208b95f  wrap jiff Timestamp
208b95f is described below

commit 208b95fd18e0fbe3f3880ee8db7eb8ea04a67aca
Author: tison <wa...@gmail.com>
AuthorDate: Thu Oct 2 23:39:38 2025 +0800

    wrap jiff Timestamp
    
    Signed-off-by: tison <wa...@gmail.com>
---
 core/src/time.rs | 169 +++++++++++++++++++++++++++++++++++++------------------
 1 file changed, 115 insertions(+), 54 deletions(-)

diff --git a/core/src/time.rs b/core/src/time.rs
index d2fd5f6..7ca0b4a 100644
--- a/core/src/time.rs
+++ b/core/src/time.rs
@@ -18,66 +18,127 @@
 //! Time related utils.
 
 use crate::Error;
+use std::ops::{Add, AddAssign, Sub, SubAssign};
+use std::time::Duration;
 
-/// DateTime is the alias for `jiff::Timestamp`.
-pub type Timestamp = jiff::Timestamp;
+/// An instant in time represented as the number of nanoseconds since the Unix epoch.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Timestamp(jiff::Timestamp);
 
-/// Create datetime of now.
-pub fn now() -> Timestamp {
-    Timestamp::now()
-}
+impl Timestamp {
+    /// Create the timestamp of now.
+    pub fn now() -> Self {
+        Self(jiff::Timestamp::now())
+    }
 
-/// Format time into date: `20220301`
-pub fn format_date(t: Timestamp) -> String {
-    t.strftime("%Y%m%d").to_string()
-}
+    /// Format the timestamp into date: `20220301`
+    pub fn format_date(self) -> String {
+        self.0.strftime("%Y%m%d").to_string()
+    }
+
+    /// Format the timestamp into ISO8601: `20220313T072004Z`
+    pub fn format_iso8601(self) -> String {
+        self.0.strftime("%Y%m%dT%H%M%SZ").to_string()
+    }
+
+    /// Format the timestamp into http date: `Sun, 06 Nov 1994 08:49:37 GMT`
+    ///
+    /// ## Note
+    ///
+    /// HTTP date is slightly different from RFC2822.
+    ///
+    /// - Timezone is fixed to GMT.
+    /// - Day must be 2 digit.
+    pub fn format_http_date(self) -> String {
+        self.0.strftime("%a, %d %b %Y %T GMT").to_string()
+    }
+
+    /// Format the timestamp into RFC3339: `2022-03-13T07:20:04Z`
+    pub fn format_rfc3339(self) -> String {
+        self.0.strftime("%FT%TZ").to_string()
+    }
 
-/// Format time into ISO8601: `20220313T072004Z`
-pub fn format_iso8601(t: Timestamp) -> String {
-    t.strftime("%Y%m%dT%H%M%SZ").to_string()
+    /// Parse a timestamp from RFC3339.
+    ///
+    /// All of them are valid time:
+    ///
+    /// - `2022-03-13T07:20:04Z`
+    /// - `2022-03-01T08:12:34+00:00`
+    /// - `2022-03-01T08:12:34.00+00:00`
+    pub fn parse_rfc3339(s: &str) -> crate::Result<Timestamp> {
+        match s.parse() {
+            Ok(t) => Ok(Timestamp(t)),
+            Err(err) => {
+                Err(Error::unexpected(format!("parse '{s}' into rfc3339 failed")).with_source(err))
+            }
+        }
+    }
+
+    /// Parse a timestamp from RFC2822.
+    ///
+    /// All of them are valid time:
+    ///
+    /// - `Sat, 13 Jul 2024 15:09:59 -0400`
+    /// - `Mon, 15 Aug 2022 16:50:12 GMT`
+    pub fn parse_rfc2822(s: &str) -> crate::Result<Timestamp> {
+        match jiff::fmt::rfc2822::parse(s) {
+            Ok(zoned) => Ok(Timestamp(zoned.timestamp())),
+            Err(err) => {
+                Err(Error::unexpected(format!("parse '{s}' into rfc2822 failed")).with_source(err))
+            }
+        }
+    }
+
+    /// Parse the string format "2023-10-31 21:59:10.000000".
+    pub fn parse_datetime_utc(s: &str) -> crate::Result<Timestamp> {
+        let dt = s.parse::<jiff::civil::DateTime>().map_err(|err| {
+            Error::unexpected(format!("parse '{s}' into datetime failed")).with_source(err)
+        })?;
+
+        let ts = jiff::tz::TimeZone::UTC.to_timestamp(dt).map_err(|err| {
+            Error::unexpected(format!("convert '{s}' into timestamp failed")).with_source(err)
+        })?;
+
+        Ok(Timestamp(ts))
+    }
 }
 
-/// Format time into http date: `Sun, 06 Nov 1994 08:49:37 GMT`
-///
-/// ## Note
-///
-/// HTTP date is slightly different from RFC2822.
-///
-/// - Timezone is fixed to GMT.
-/// - Day must be 2 digit.
-pub fn format_http_date(t: Timestamp) -> String {
-    t.strftime("%a, %d %b %Y %T GMT").to_string()
+impl Add<Duration> for Timestamp {
+    type Output = Timestamp;
+
+    fn add(self, rhs: Duration) -> Timestamp {
+        let ts = self
+            .0
+            .checked_add(rhs)
+            .expect("adding unsigned duration to timestamp overflowed");
+
+        Timestamp(ts)
+    }
 }
 
-/// Format time into RFC3339: `2022-03-13T07:20:04Z`
-pub fn format_rfc3339(t: Timestamp) -> String {
-    t.strftime("%FT%TZ").to_string()
+impl AddAssign<Duration> for Timestamp {
+    fn add_assign(&mut self, rhs: Duration) {
+        *self = *self + rhs
+    }
 }
 
-/// Parse time from RFC3339.
-///
-/// All of them are valid time:
-///
-/// - `2022-03-13T07:20:04Z`
-/// - `2022-03-01T08:12:34+00:00`
-/// - `2022-03-01T08:12:34.00+00:00`
-pub fn parse_rfc3339(s: &str) -> crate::Result<Timestamp> {
-    s.parse().map_err(|err| {
-        Error::unexpected(format!("parse '{s}' into rfc3339 failed")).with_source(err)
-    })
+impl Sub<Duration> for Timestamp {
+    type Output = Timestamp;
+
+    fn sub(self, rhs: Duration) -> Timestamp {
+        let ts = self
+            .0
+            .checked_sub(rhs)
+            .expect("subtracting unsigned duration from timestamp overflowed");
+
+        Timestamp(ts)
+    }
 }
 
-/// Parse time from RFC2822.
-///
-/// All of them are valid time:
-///
-/// - `Sat, 13 Jul 2024 15:09:59 -0400`
-/// - `Mon, 15 Aug 2022 16:50:12 GMT`
-pub fn parse_rfc2822(s: &str) -> crate::Result<Timestamp> {
-    let zoned = jiff::fmt::rfc2822::parse(s).map_err(|err| {
-        Error::unexpected(format!("parse '{s}' into rfc2822 failed")).with_source(err)
-    })?;
-    Ok(zoned.timestamp())
+impl SubAssign<Duration> for Timestamp {
+    fn sub_assign(&mut self, rhs: Duration) {
+        *self = *self - rhs
+    }
 }
 
 #[cfg(test)]
@@ -85,31 +146,31 @@ mod tests {
     use super::*;
 
     fn test_time() -> Timestamp {
-        "2022-03-01T08:12:34Z".parse().unwrap()
+        Timestamp("2022-03-01T08:12:34Z".parse().unwrap())
     }
 
     #[test]
     fn test_format_date() {
         let t = test_time();
-        assert_eq!("20220301", format_date(t))
+        assert_eq!("20220301", t.format_date())
     }
 
     #[test]
     fn test_format_ios8601() {
         let t = test_time();
-        assert_eq!("20220301T081234Z", format_iso8601(t))
+        assert_eq!("20220301T081234Z", t.format_iso8601())
     }
 
     #[test]
     fn test_format_http_date() {
         let t = test_time();
-        assert_eq!("Tue, 01 Mar 2022 08:12:34 GMT", format_http_date(t))
+        assert_eq!("Tue, 01 Mar 2022 08:12:34 GMT", t.format_http_date())
     }
 
     #[test]
     fn test_format_rfc3339() {
         let t = test_time();
-        assert_eq!("2022-03-01T08:12:34Z", format_rfc3339(t))
+        assert_eq!("2022-03-01T08:12:34Z", t.format_rfc3339())
     }
 
     #[test]
@@ -121,7 +182,7 @@ mod tests {
             "2022-03-01T08:12:34+00:00",
             "2022-03-01T08:12:34.00+00:00",
         ] {
-            assert_eq!(t, parse_rfc3339(v).expect("must be valid time"));
+            assert_eq!(t, Timestamp::parse_rfc3339(v).expect("must be valid time"));
         }
     }
 }