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

xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git


The following commit(s) were added to refs/heads/main by this push:
     new ca54fab81 refactor: Centralize date/time handling with Timestamp 
wrapper (#6650)
ca54fab81 is described below

commit ca54fab8138fe259d6669a636c0b5fd0dfffa21a
Author: dami0806 <[email protected]>
AuthorDate: Tue Oct 14 14:31:12 2025 +0900

    refactor: Centralize date/time handling with Timestamp wrapper (#6650)
    
    * refactor(raw): add Timestamp wrapper around jiff::Timestamp
    
      Introduce a new Timestamp newtype wrapper around jiff::Timestamp
      to provide a more ergonomic and type-safe API for time operations
      across OpenDAL.
    
      Key features:
      - Wraps jiff::Timestamp with a thin newtype pattern
      - Implements common conversion traits (From, TryFrom, FromStr)
      - Provides formatting methods (format_http_date, format_rfc3339, etc)
      - Adds helper constructors (now, from_millisecond, from_second)
      - Maintains compatibility with SystemTime and Duration
    
      This wrapper simplifies time handling and makes the API more consistent
      throughout the codebase while preserving all jiff functionality.
    
    * refactor(raw): remove jiff_util module and expose time module
    
      Replace the old jiff_util module with the new time module.
      Update module exports to use the new Timestamp wrapper type.
    
    * refactor(raw): migrate raw utilities to use Timestamp wrapper
    
      Update raw layer utilities to use the new Timestamp wrapper:
      - typed_kv/api: Use Timestamp for key-value metadata
      - http_util/header: Use Timestamp formatting methods
      - ops: Update operation metadata to use Timestamp
    
    * refactor(types): migrate types layer to use Timestamp wrapper
    
      Update types layer to use the new Timestamp wrapper:
      - metadata: Use Timestamp for file metadata timestamps
      - options: Use Timestamp for conditional request options
      - operator_futures: Use Timestamp in future option builders
    
    * refactor(services): migrate cloud
      storage services to Timestamp wrapper
    
      Update AWS S3, Google GCS, Azure Blob/DLS/File,
      Tencent COS,
      Alibaba OSS, Backblaze B2, Aliyun Drive, Vercel
      Blob, and
      Cloudflare KV services to use the new Timestamp
      wrapper.
    
      Changes include:
      - Migrate core service logic to use Timestamp
      - Update listers to use Timestamp parsing
      - Replace parse_datetime_from_* helpers with
      Timestamp methods
    
    * refactor(services): migrate
      filesystem services to Timestamp wrapper
    
      Update local fs, HDFS, HDFS native, SFTP, WebHDFS,
       WebDAV, FTP,
      MonoioFS, Alluxio, and CompFS services to use the
      new Timestamp wrapper.
    
      Changes include:
      - Migrate SystemTime conversions to use Timestamp
      - Update file metadata handling with Timestamp
      - Update listers and writers to use Timestamp
      methods
    
    * refactor(services): migrate other
      services to Timestamp wrapper
    
      Update Dropbox, OneDrive, Google Drive, pCloud,
      GitHub, Hugging Face,
      Koofr, LakeFS, Seafile, Yandex Disk, UpYun, Swift,
       cacache, dashmap,
      mini_moka, and DBFS services to use the new
      Timestamp wrapper.
    
      Changes include:
      - Migrate cloud drive services to use Timestamp
      - Update cache services with Timestamp handling
      - Update listers and writers across all services
    
    * chore: update bin/ofs Cargo.lock
      after Timestamp refactor
    
    * fix(bindings/java): migrate to use
      Timestamp wrapper
    
    * fix(bindings/python): migrate to
      use Timestamp wrapper
    
    * fix(bindings/nodejs): replace
      parse_datetime_from_rfc3339 with
      Timestamp::from_str
    
      The parse_datetime_from_rfc3339 helper function
      was removed as part of
      the Timestamp wrapper introduction. Now using the
      FromStr trait
      implementation on Timestamp directly.
    
    * fix(bindings/c): use into_inner()
      to access jiff Timestamp methods
    
      The Timestamp wrapper doesn't expose all
      jiff::Timestamp methods directly.
      Use into_inner() to access the underlying
      jiff::Timestamp when needed,
      such as for as_millisecond().
    
    * fix(integrations/object_store):
      update timestamp conversion helpers
    
      Update timestamp_to_datetime and
      datetime_to_timestamp helper functions
      to use opendal::raw::Timestamp wrapper instead of
      jiff::Timestamp directly.
      Convert to/from jiff::Timestamp internally for
      chrono interoperability.
    
    * fix(bindings): resolve additional
      CI compilation errors
    
      - C bindings: Calculate milliseconds from
      Timestamp using as_second() and
      subsec_nanosecond()
      - Python bindings: Change Timestamp to String for
      PyO3 compatibility
      - dav-server integration: Use as_system_time() for
       Timestamp to SystemTime conversion
    
    * refactor: add as_millisecond to Timestamp and fix bindings
    
    Add as_millisecond() method to Timestamp wrapper and update C bindings
    and object_store integration to use proper wrapper methods instead of
    manual calculations. Revert Python String workaround back to Timestamp.
    
    * feat(bindings/python): add Timestamp wrapper for datetime conversion
    
    Add Timestamp wrapper in Python bindings to convert opendal::raw::Timestamp
    to/from Python datetime using PyO3's jiff-02 feature.
    
    * fix(integrations/fuse3): use into_inner for Timestamp to SystemTime 
conversion
    
    Use into_inner() to convert Timestamp to jiff::Timestamp, which can then
    be converted to SystemTime.
    
    * chore(fmt): apply rustfmt for object_store
    
    * fix(integrations/unftp-sbe): use into_inner for Timestamp to SystemTime 
conversion
    
    * fine tune boundary
    
    Signed-off-by: tison <[email protected]>
    
    * fixup ci
    
    Signed-off-by: tison <[email protected]>
    
    * fmt
    
    Signed-off-by: tison <[email protected]>
    
    ---------
    
    Signed-off-by: tison <[email protected]>
    Co-authored-by: tison <[email protected]>
---
 bin/oay/Cargo.lock                          |   1 -
 bin/oay/Cargo.toml                          |   1 -
 bin/ofs/Cargo.lock                          |   4 +-
 bindings/c/src/metadata.rs                  |   2 +-
 bindings/cpp/Cargo.toml                     |   1 -
 bindings/haskell/Cargo.toml                 |   1 -
 bindings/java/Cargo.toml                    |   1 -
 bindings/java/src/convert.rs                |  22 +-
 bindings/java/src/lib.rs                    |   4 +-
 bindings/nodejs/src/options.rs              |  14 +-
 bindings/ocaml/src/operator/metadata.rs     |   5 +-
 bindings/python/src/metadata.rs             |   5 +-
 bindings/python/src/options.rs              |  21 +-
 core/src/lib.rs                             |   1 -
 core/src/raw/adapters/typed_kv/api.rs       |   3 +-
 core/src/raw/http_util/header.rs            |   3 +-
 core/src/raw/jiff_util.rs                   | 115 ----------
 core/src/raw/mod.rs                         |   4 +-
 core/src/raw/ops.rs                         |   1 -
 core/src/raw/time.rs                        | 325 ++++++++++++++++++++++++++++
 core/src/services/aliyun_drive/backend.rs   |   1 -
 core/src/services/aliyun_drive/core.rs      |   6 +-
 core/src/services/aliyun_drive/lister.rs    |   1 -
 core/src/services/alluxio/core.rs           |   2 +-
 core/src/services/azblob/core.rs            |  10 +-
 core/src/services/azblob/lister.rs          |   2 +-
 core/src/services/azdls/lister.rs           |   2 +-
 core/src/services/azfile/lister.rs          |   4 +-
 core/src/services/b2/core.rs                |   1 -
 core/src/services/cacache/backend.rs        |   7 +-
 core/src/services/cloudflare_kv/backend.rs  |   3 +-
 core/src/services/cloudflare_kv/lister.rs   |   2 +-
 core/src/services/cloudflare_kv/writer.rs   |   4 +-
 core/src/services/compfs/backend.rs         |   2 +-
 core/src/services/cos/core.rs               |  10 +-
 core/src/services/cos/lister.rs             |   8 +-
 core/src/services/dashmap/writer.rs         |   4 +-
 core/src/services/dbfs/backend.rs           |   2 +-
 core/src/services/dbfs/lister.rs            |   8 +-
 core/src/services/dropbox/backend.rs        |   2 +-
 core/src/services/dropbox/builder.rs        |   1 -
 core/src/services/dropbox/core.rs           |   1 -
 core/src/services/dropbox/lister.rs         |   2 +-
 core/src/services/fs/core.rs                |   2 +-
 core/src/services/fs/writer.rs              |   4 +-
 core/src/services/ftp/backend.rs            |   2 +-
 core/src/services/ftp/lister.rs             |   2 +-
 core/src/services/gcs/core.rs               |  15 +-
 core/src/services/gcs/lister.rs             |   2 +-
 core/src/services/gdrive/backend.rs         |   1 -
 core/src/services/gdrive/builder.rs         |   2 +-
 core/src/services/gdrive/core.rs            |   1 -
 core/src/services/github/core.rs            |   1 -
 core/src/services/hdfs/backend.rs           |   2 +-
 core/src/services/hdfs/lister.rs            |   2 +-
 core/src/services/hdfs_native/backend.rs    |   2 +-
 core/src/services/hdfs_native/lister.rs     |   4 +-
 core/src/services/huggingface/backend.rs    |   4 +-
 core/src/services/huggingface/lister.rs     |   2 +-
 core/src/services/koofr/backend.rs          |   2 +-
 core/src/services/koofr/lister.rs           |   2 +-
 core/src/services/lakefs/backend.rs         |   1 -
 core/src/services/lakefs/lister.rs          |   1 -
 core/src/services/mini_moka/writer.rs       |   1 -
 core/src/services/monoiofs/backend.rs       |   2 +-
 core/src/services/monoiofs/writer.rs        |   2 +-
 core/src/services/onedrive/builder.rs       |   2 +-
 core/src/services/onedrive/core.rs          |   3 +-
 core/src/services/onedrive/lister.rs        |   3 +-
 core/src/services/onedrive/writer.rs        |   4 +-
 core/src/services/oss/core.rs               |  10 +-
 core/src/services/oss/lister.rs             |  10 +-
 core/src/services/pcloud/core.rs            |   4 +-
 core/src/services/s3/core.rs                |  20 +-
 core/src/services/s3/lister.rs              |  13 +-
 core/src/services/seafile/core.rs           |   4 +-
 core/src/services/seafile/lister.rs         |   2 +-
 core/src/services/sftp/utils.rs             |   4 +-
 core/src/services/swift/lister.rs           |   2 +-
 core/src/services/upyun/core.rs             |   5 +-
 core/src/services/upyun/lister.rs           |   2 +-
 core/src/services/vercel_blob/core.rs       |   2 +-
 core/src/services/webdav/core.rs            |   2 +-
 core/src/services/webhdfs/backend.rs        |   2 +-
 core/src/services/webhdfs/lister.rs         |   4 +-
 core/src/services/yandex_disk/core.rs       |   2 +-
 core/src/types/metadata.rs                  |   1 -
 core/src/types/operator/operator_futures.rs |  17 +-
 core/src/types/options.rs                   |   3 +-
 integrations/cloud_filter/src/lib.rs        |   6 +-
 integrations/dav-server/src/metadata.rs     |   4 +-
 integrations/fuse3/src/file_system.rs       |   5 +-
 integrations/object_store/Cargo.toml        |   1 -
 integrations/object_store/src/lib.rs        |  12 +-
 integrations/unftp-sbe/src/lib.rs           |   9 +-
 95 files changed, 487 insertions(+), 349 deletions(-)

diff --git a/bin/oay/Cargo.lock b/bin/oay/Cargo.lock
index ec05882b4..8cfaba4f4 100644
--- a/bin/oay/Cargo.lock
+++ b/bin/oay/Cargo.lock
@@ -1049,7 +1049,6 @@ dependencies = [
  "dav-server",
  "dav-server-opendalfs",
  "futures-util",
- "jiff",
  "log",
  "logforth",
  "opendal",
diff --git a/bin/oay/Cargo.toml b/bin/oay/Cargo.toml
index b0cf4fdfc..baf1ba434 100644
--- a/bin/oay/Cargo.toml
+++ b/bin/oay/Cargo.toml
@@ -45,7 +45,6 @@ axum = { version = "0.8.6" }
 dav-server = { version = "0.8", optional = true }
 dav-server-opendalfs = { version = "0.6.0", path = 
"../../integrations/dav-server", optional = true }
 futures-util = { version = "0.3.29", optional = true }
-jiff = { version = "0.2.15" }
 log = { version = "0.4.27" }
 logforth = { version = "0.28.1", features = ["starter-log"] }
 opendal = { version = "0.54.0", path = "../../core", features = [
diff --git a/bin/ofs/Cargo.lock b/bin/ofs/Cargo.lock
index 43146b5d6..ac86329d3 100644
--- a/bin/ofs/Cargo.lock
+++ b/bin/ofs/Cargo.lock
@@ -1,6 +1,6 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "addr2line"
@@ -1296,13 +1296,13 @@ dependencies = [
  "backon",
  "base64",
  "bytes",
- "chrono",
  "crc32c",
  "dotenvy",
  "futures",
  "getrandom 0.2.16",
  "http",
  "http-body",
+ "jiff",
  "log",
  "md-5",
  "percent-encoding",
diff --git a/bindings/c/src/metadata.rs b/bindings/c/src/metadata.rs
index a47407053..8ace23f38 100644
--- a/bindings/c/src/metadata.rs
+++ b/bindings/c/src/metadata.rs
@@ -131,7 +131,7 @@ impl opendal_metadata {
         let mtime = self.deref().last_modified();
         match mtime {
             None => -1,
-            Some(time) => time.as_millisecond(),
+            Some(time) => time.into_inner().as_millisecond(),
         }
     }
 }
diff --git a/bindings/cpp/Cargo.toml b/bindings/cpp/Cargo.toml
index e9e5cf69f..169234739 100644
--- a/bindings/cpp/Cargo.toml
+++ b/bindings/cpp/Cargo.toml
@@ -34,7 +34,6 @@ anyhow = { version = "1.0.100" }
 cxx = { version = "1.0.186" }
 cxx-async = { version = "0.1.3", optional = true }
 futures = { version = "0.3.31" }
-jiff = { version = "0.2.15" }
 # this crate won't be published, we always use the local version
 opendal = { version = ">=0", path = "../../core", features = ["blocking"] }
 tokio = { version = "1.27", features = ["fs", "macros", "rt-multi-thread"] }
diff --git a/bindings/haskell/Cargo.toml b/bindings/haskell/Cargo.toml
index 8cd44f0f4..4b83eb96d 100644
--- a/bindings/haskell/Cargo.toml
+++ b/bindings/haskell/Cargo.toml
@@ -31,7 +31,6 @@ crate-type = ["cdylib"]
 doc = false
 
 [dependencies]
-jiff = { version = "0.2.15" }
 log = { version = "0.4", features = ["std"] }
 # this crate won't be published, we always use the local version
 opendal = { version = ">=0", path = "../../core", features = [
diff --git a/bindings/java/Cargo.toml b/bindings/java/Cargo.toml
index 0d83468ac..6fc300e75 100644
--- a/bindings/java/Cargo.toml
+++ b/bindings/java/Cargo.toml
@@ -151,7 +151,6 @@ services-compfs = ["opendal/services-compfs"]
 
 [dependencies]
 anyhow = { version = "1.0.100" }
-jiff = { version = "0.2.15" }
 jni = { version = "0.21.1" }
 # this crate won't be published, we always use the local version
 opendal = { version = ">=0", path = "../../core", features = [
diff --git a/bindings/java/src/convert.rs b/bindings/java/src/convert.rs
index bd0706e4a..124d6c42e 100644
--- a/bindings/java/src/convert.rs
+++ b/bindings/java/src/convert.rs
@@ -16,7 +16,6 @@
 // under the License.
 
 use crate::Result;
-use jiff::Timestamp;
 use jni::JNIEnv;
 use jni::objects::JObject;
 use jni::objects::JString;
@@ -127,7 +126,7 @@ pub(crate) fn read_instant_field_to_timestamp(
     env: &mut JNIEnv<'_>,
     obj: &JObject,
     field: &str,
-) -> Result<Option<Timestamp>> {
+) -> Result<Option<opendal::raw::Timestamp>> {
     let result = env.get_field(obj, field, "Ljava/time/Instant;")?.l()?;
     if result.is_null() {
         return Ok(None);
@@ -137,14 +136,17 @@ pub(crate) fn read_instant_field_to_timestamp(
         .call_method(&result, "getEpochSecond", "()J", &[])?
         .j()?;
     let nano = env.call_method(&result, "getNano", "()I", &[])?.i()?;
-    Timestamp::new(epoch_second, nano).map(Some).map_err(|err| {
-        Error::new(
-            ErrorKind::Unexpected,
-            format!("invalid timestamp: seconds={epoch_second}, nanos={nano}"),
-        )
-        .set_source(err)
-        .into()
-    })
+
+    opendal::raw::Timestamp::from_second(epoch_second)
+        .map(Some)
+        .map_err(|err| {
+            Error::new(
+                ErrorKind::Unexpected,
+                format!("invalid timestamp: seconds={epoch_second}, 
nanos={nano}"),
+            )
+            .set_source(err)
+            .into()
+        })
 }
 
 pub(crate) fn offset_length_to_range(offset: i64, length: i64) -> 
Result<(Bound<u64>, Bound<u64>)> {
diff --git a/bindings/java/src/lib.rs b/bindings/java/src/lib.rs
index 027fb5b8b..f1a2896da 100644
--- a/bindings/java/src/lib.rs
+++ b/bindings/java/src/lib.rs
@@ -156,8 +156,8 @@ fn make_metadata<'a>(env: &mut JNIEnv<'a>, metadata: 
Metadata) -> Result<JObject
                     "ofEpochSecond",
                     "(JJ)Ljava/time/Instant;",
                     &[
-                        JValue::Long(v.as_second()),
-                        JValue::Long(v.subsec_nanosecond() as jlong),
+                        JValue::Long(v.into_inner().as_second()),
+                        JValue::Long(v.into_inner().subsec_nanosecond() as 
jlong),
                     ],
                 )?
                 .l()?)
diff --git a/bindings/nodejs/src/options.rs b/bindings/nodejs/src/options.rs
index 1ba84582e..8331d393a 100644
--- a/bindings/nodejs/src/options.rs
+++ b/bindings/nodejs/src/options.rs
@@ -16,7 +16,7 @@
 // under the License.
 
 use napi::bindgen_prelude::BigInt;
-use opendal::raw::{BytesRange, parse_datetime_from_rfc3339};
+use opendal::raw::{BytesRange, Timestamp};
 use std::collections::HashMap;
 
 #[napi(object)]
@@ -79,10 +79,10 @@ impl From<StatOptions> for opendal::options::StatOptions {
     fn from(value: StatOptions) -> Self {
         let if_modified_since = value
             .if_modified_since
-            .and_then(|v| parse_datetime_from_rfc3339(&v).ok());
+            .and_then(|v| v.parse::<Timestamp>().ok());
         let if_unmodified_since = value
             .if_unmodified_since
-            .and_then(|v| parse_datetime_from_rfc3339(&v).ok());
+            .and_then(|v| v.parse::<Timestamp>().ok());
 
         Self {
             if_modified_since,
@@ -215,10 +215,10 @@ impl From<ReadOptions> for opendal::options::ReadOptions {
         let range = value.make_range();
         let if_modified_since = value
             .if_modified_since
-            .and_then(|v| parse_datetime_from_rfc3339(&v).ok());
+            .and_then(|v| v.parse::<Timestamp>().ok());
         let if_unmodified_since = value
             .if_unmodified_since
-            .and_then(|v| parse_datetime_from_rfc3339(&v).ok());
+            .and_then(|v| v.parse::<Timestamp>().ok());
 
         Self {
             version: value.version,
@@ -329,10 +329,10 @@ impl From<ReaderOptions> for 
opendal::options::ReaderOptions {
     fn from(value: ReaderOptions) -> Self {
         let if_modified_since = value
             .if_modified_since
-            .and_then(|v| parse_datetime_from_rfc3339(&v).ok());
+            .and_then(|v| v.parse::<Timestamp>().ok());
         let if_unmodified_since = value
             .if_unmodified_since
-            .and_then(|v| parse_datetime_from_rfc3339(&v).ok());
+            .and_then(|v| v.parse::<Timestamp>().ok());
 
         Self {
             version: value.version,
diff --git a/bindings/ocaml/src/operator/metadata.rs 
b/bindings/ocaml/src/operator/metadata.rs
index 5dfb9975e..c7cd3d3c7 100644
--- a/bindings/ocaml/src/operator/metadata.rs
+++ b/bindings/ocaml/src/operator/metadata.rs
@@ -62,5 +62,8 @@ pub fn metadata_etag(metadata: &mut Metadata) -> 
Option<String> {
 #[ocaml::func]
 #[ocaml::sig("metadata -> int64 option ")]
 pub fn metadata_last_modified(metadata: &mut Metadata) -> Option<i64> {
-    metadata.0.last_modified().map(|t| t.as_second())
+    metadata
+        .0
+        .last_modified()
+        .map(|t| t.into_inner().as_second())
 }
diff --git a/bindings/python/src/metadata.rs b/bindings/python/src/metadata.rs
index c15eb77ba..3c9d33a17 100644
--- a/bindings/python/src/metadata.rs
+++ b/bindings/python/src/metadata.rs
@@ -16,7 +16,6 @@
 // under the License.
 
 use crate::*;
-use jiff::Timestamp;
 use std::collections::HashMap;
 
 #[pyclass(module = "opendal")]
@@ -121,8 +120,8 @@ impl Metadata {
 
     /// Last modified time
     #[getter]
-    pub fn last_modified(&self) -> Option<Timestamp> {
-        self.0.last_modified()
+    pub fn last_modified(&self) -> Option<jiff::Timestamp> {
+        self.0.last_modified().map(Into::into)
     }
 
     /// Version of this entry, if available.
diff --git a/bindings/python/src/options.rs b/bindings/python/src/options.rs
index b40226268..fa5f74061 100644
--- a/bindings/python/src/options.rs
+++ b/bindings/python/src/options.rs
@@ -16,7 +16,6 @@
 // under the License.
 
 use dict_derive::FromPyObject;
-use jiff::Timestamp;
 use opendal::{self as ocore, raw::BytesRange};
 use pyo3::pyclass;
 use std::collections::HashMap;
@@ -33,8 +32,8 @@ pub struct ReadOptions {
     pub size: Option<usize>,
     pub if_match: Option<String>,
     pub if_none_match: Option<String>,
-    pub if_modified_since: Option<Timestamp>,
-    pub if_unmodified_since: Option<Timestamp>,
+    pub if_modified_since: Option<jiff::Timestamp>,
+    pub if_unmodified_since: Option<jiff::Timestamp>,
     pub content_type: Option<String>,
     pub cache_control: Option<String>,
     pub content_disposition: Option<String>,
@@ -72,8 +71,8 @@ impl From<ReadOptions> for ocore::options::ReadOptions {
             version: opts.version,
             if_match: opts.if_match,
             if_none_match: opts.if_none_match,
-            if_modified_since: opts.if_modified_since,
-            if_unmodified_since: opts.if_unmodified_since,
+            if_modified_since: opts.if_modified_since.map(Into::into),
+            if_unmodified_since: opts.if_unmodified_since.map(Into::into),
             concurrent: opts.concurrent.unwrap_or_default(),
             chunk: opts.chunk,
             gap: opts.gap,
@@ -90,8 +89,8 @@ impl From<ReadOptions> for ocore::options::ReaderOptions {
             version: opts.version,
             if_match: opts.if_match,
             if_none_match: opts.if_none_match,
-            if_modified_since: opts.if_modified_since,
-            if_unmodified_since: opts.if_unmodified_since,
+            if_modified_since: opts.if_modified_since.map(Into::into),
+            if_unmodified_since: opts.if_unmodified_since.map(Into::into),
             concurrent: opts.concurrent.unwrap_or_default(),
             chunk: opts.chunk,
             gap: opts.gap,
@@ -146,8 +145,8 @@ pub struct StatOptions {
     pub version: Option<String>,
     pub if_match: Option<String>,
     pub if_none_match: Option<String>,
-    pub if_modified_since: Option<Timestamp>,
-    pub if_unmodified_since: Option<Timestamp>,
+    pub if_modified_since: Option<jiff::Timestamp>,
+    pub if_unmodified_since: Option<jiff::Timestamp>,
     pub content_type: Option<String>,
     pub cache_control: Option<String>,
     pub content_disposition: Option<String>,
@@ -159,8 +158,8 @@ impl From<StatOptions> for ocore::options::StatOptions {
             version: opts.version,
             if_match: opts.if_match,
             if_none_match: opts.if_none_match,
-            if_modified_since: opts.if_modified_since,
-            if_unmodified_since: opts.if_unmodified_since,
+            if_modified_since: opts.if_modified_since.map(Into::into),
+            if_unmodified_since: opts.if_unmodified_since.map(Into::into),
             override_content_type: opts.content_type,
             override_cache_control: opts.cache_control,
             override_content_disposition: opts.content_disposition,
diff --git a/core/src/lib.rs b/core/src/lib.rs
index 80797ad94..cd53ad3f7 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -19,7 +19,6 @@
     html_logo_url = 
"https://raw.githubusercontent.com/apache/opendal/main/website/static/img/logo.svg";
 )]
 #![cfg_attr(docsrs, feature(doc_cfg))]
-#![cfg_attr(docsrs, doc(auto_cfg))]
 //! Apache OpenDALâ„¢ is an Open Data Access Layer that enables seamless 
interaction with diverse storage services.
 //!
 //! OpenDAL's development is guided by its vision of **One Layer, All 
Storage** and its core principles: **Open Community**, **Solid Foundation**, 
**Fast Access**, **Object Storage First**, and **Extensible Architecture**. 
Read the explained vision at [OpenDAL 
Vision](https://opendal.apache.org/vision).
diff --git a/core/src/raw/adapters/typed_kv/api.rs 
b/core/src/raw/adapters/typed_kv/api.rs
index a8cd8f884..ab1e63d87 100644
--- a/core/src/raw/adapters/typed_kv/api.rs
+++ b/core/src/raw/adapters/typed_kv/api.rs
@@ -22,8 +22,7 @@ use crate::ErrorKind;
 use crate::Metadata;
 use crate::Result;
 use crate::Scheme;
-use crate::raw::MaybeSend;
-use jiff::Timestamp;
+use crate::raw::{MaybeSend, Timestamp};
 use std::fmt::Debug;
 use std::future::Future;
 use std::future::ready;
diff --git a/core/src/raw/http_util/header.rs b/core/src/raw/http_util/header.rs
index 09adf864c..bc406f84b 100644
--- a/core/src/raw/http_util/header.rs
+++ b/core/src/raw/http_util/header.rs
@@ -31,7 +31,6 @@ use http::header::CONTENT_TYPE;
 use http::header::ETAG;
 use http::header::LAST_MODIFIED;
 use http::header::LOCATION;
-use jiff::Timestamp;
 use md5::Digest;
 
 use crate::EntryMode;
@@ -95,7 +94,7 @@ pub fn parse_content_range(headers: &HeaderMap) -> 
Result<Option<BytesContentRan
 /// Parse last modified from header map.
 pub fn parse_last_modified(headers: &HeaderMap) -> Result<Option<Timestamp>> {
     parse_header_to_str(headers, LAST_MODIFIED)?
-        .map(parse_datetime_from_rfc2822)
+        .map(Timestamp::parse_rfc2822)
         .transpose()
 }
 
diff --git a/core/src/raw/jiff_util.rs b/core/src/raw/jiff_util.rs
deleted file mode 100644
index 9c2b9f75e..000000000
--- a/core/src/raw/jiff_util.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-use crate::*;
-use std::time::SystemTime;
-
-use jiff::Timestamp;
-
-/// Parse datetime from rfc2822.
-///
-/// For example: `Fri, 28 Nov 2014 21:00:09 +0900`
-pub fn parse_datetime_from_rfc2822(s: &str) -> Result<Timestamp> {
-    match jiff::fmt::rfc2822::parse(s) {
-        Ok(zoned) => Ok(zoned.timestamp()),
-        Err(err) => Err(Error::new(
-            ErrorKind::Unexpected,
-            format!("parse '{s}' from rfc2822 failed"),
-        )
-        .set_source(err)),
-    }
-}
-
-/// Parse datetime from rfc3339.
-///
-/// # Examples
-///
-/// With a time zone:
-///
-/// ```
-/// use jiff::tz::TimeZone;
-/// use opendal::raw::parse_datetime_from_rfc3339;
-/// use opendal::Error;
-///
-/// let date_time = parse_datetime_from_rfc3339("2014-11-28T21:00:09+09:00")?;
-/// assert_eq!(date_time.to_zoned(TimeZone::UTC).day(), 28);
-/// # Ok::<(), Error>(())
-/// ```
-///
-/// With the UTC offset of 00:00:
-///
-/// ```
-/// use jiff::tz::TimeZone;
-/// use opendal::Error;
-/// use opendal::raw::parse_datetime_from_rfc3339;
-///
-/// let date_time = parse_datetime_from_rfc3339("2014-11-28T21:00:09Z")?;
-/// assert_eq!(date_time.to_zoned(TimeZone::UTC).hour(), 21);
-/// # Ok::<(), Error>(())
-/// ```
-pub fn parse_datetime_from_rfc3339(s: &str) -> Result<Timestamp> {
-    match s.parse() {
-        Ok(t) => Ok(t),
-        Err(err) => Err(Error::new(
-            ErrorKind::Unexpected,
-            format!("parse '{s}' into timestamp failed"),
-        )
-        .set_source(err)),
-    }
-}
-
-/// parse datetime from given timestamp_millis
-pub fn parse_datetime_from_timestamp_millis(millis: i64) -> Result<Timestamp> {
-    Timestamp::from_millisecond(millis).map_err(|err| {
-        Error::new(ErrorKind::Unexpected, "input timestamp 
overflow").set_source(err)
-    })
-}
-
-/// parse datetime from given timestamp_secs
-pub fn parse_datetime_from_timestamp(secs: i64) -> Result<Timestamp> {
-    Timestamp::from_second(secs).map_err(|err| {
-        Error::new(ErrorKind::Unexpected, "input timestamp 
overflow").set_source(err)
-    })
-}
-
-/// parse datetime from given system time
-pub fn parse_datetime_from_system_time(t: SystemTime) -> Result<Timestamp> {
-    Timestamp::try_from(t).map_err(|err| {
-        Error::new(ErrorKind::Unexpected, "input timestamp 
overflow").set_source(err)
-    })
-}
-
-/// format datetime into http date, this format is required by:
-/// https://httpwg.org/specs/rfc9110.html#field.if-modified-since
-pub fn format_datetime_into_http_date(s: Timestamp) -> String {
-    s.strftime("%a, %d %b %Y %H:%M:%S GMT").to_string()
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn test_format_datetime_into_http_date() {
-        let s = "Sat, 29 Oct 1994 19:43:31 +0000";
-        let v = parse_datetime_from_rfc2822(s).unwrap();
-        assert_eq!(
-            format_datetime_into_http_date(v),
-            "Sat, 29 Oct 1994 19:43:31 GMT"
-        );
-    }
-}
diff --git a/core/src/raw/mod.rs b/core/src/raw/mod.rs
index 22879d3a9..7c6a62e71 100644
--- a/core/src/raw/mod.rs
+++ b/core/src/raw/mod.rs
@@ -71,8 +71,8 @@ pub use http_util::*;
 mod serde_util;
 pub use serde_util::*;
 
-mod jiff_util;
-pub use jiff_util::*;
+mod time;
+pub use time::Timestamp;
 
 #[cfg(feature = "internal-tokio-rt")]
 mod tokio_util;
diff --git a/core/src/raw/ops.rs b/core/src/raw/ops.rs
index afab131ca..cc206fbd2 100644
--- a/core/src/raw/ops.rs
+++ b/core/src/raw/ops.rs
@@ -21,7 +21,6 @@
 
 use crate::options;
 use crate::raw::*;
-use jiff::Timestamp;
 use std::collections::HashMap;
 use std::time::Duration;
 
diff --git a/core/src/raw/time.rs b/core/src/raw/time.rs
new file mode 100644
index 000000000..3225f270a
--- /dev/null
+++ b/core/src/raw/time.rs
@@ -0,0 +1,325 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+//! Time related utils.
+
+use crate::*;
+use std::fmt;
+use std::ops::{Add, AddAssign, Sub, SubAssign};
+use std::str::FromStr;
+use std::time::{Duration, SystemTime};
+
+/// An instant in time represented as the number of nanoseconds since the Unix 
epoch.
+#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Timestamp(jiff::Timestamp);
+
+impl FromStr for Timestamp {
+    type Err = Error;
+
+    /// Parse a timestamp by the default [`DateTimeParser`].
+    ///
+    /// 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`
+    /// - `2022-07-08T02:14:07+02:00[Europe/Paris]`
+    ///
+    /// [`DateTimeParser`]: jiff::fmt::temporal::DateTimeParser
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s.parse() {
+            Ok(t) => Ok(Timestamp(t)),
+            Err(err) => Err(Error::new(
+                ErrorKind::Unexpected,
+                format!("parse '{s}' into timestamp failed"),
+            )
+            .set_source(err)),
+        }
+    }
+}
+
+impl fmt::Display for Timestamp {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.0)
+    }
+}
+
+impl Timestamp {
+    /// The minimum timestamp value.
+    pub const MIN: Self = Self(jiff::Timestamp::MIN);
+
+    /// The maximum timestamp value.
+    pub const MAX: Self = Self(jiff::Timestamp::MAX);
+
+    /// Create the timestamp of now.
+    pub fn now() -> Self {
+        Self(jiff::Timestamp::now())
+    }
+
+    /// 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 in Zulu: `2022-03-13T07:20:04Z`
+    pub fn format_rfc3339_zulu(self) -> String {
+        self.0.strftime("%FT%TZ").to_string()
+    }
+
+    /// Convert to `SystemTime`.
+    pub fn as_system_time(self) -> SystemTime {
+        SystemTime::from(self.0)
+    }
+
+    /// Creates a new instant in time from the number of seconds elapsed since 
the Unix epoch.
+    ///
+    /// When second is negative, it corresponds to an instant in time before 
the Unix epoch.
+    /// A smaller number corresponds to an instant in time further into the 
past.
+    pub fn new(second: i64, nanosecond: i32) -> Result<Self, Error> {
+        match jiff::Timestamp::new(second, nanosecond) {
+            Ok(t) => Ok(Timestamp(t)),
+            Err(err) => Err(Error::new(
+                ErrorKind::Unexpected,
+                format!(
+                    "create timestamp from '{second}' seconds and 
'{nanosecond}' nanoseconds failed"
+                ),
+            )
+            .set_source(err)),
+        }
+    }
+
+    /// Creates a new instant in time from the number of milliseconds elapsed
+    /// since the Unix epoch.
+    ///
+    /// When `millisecond` is negative, it corresponds to an instant in time
+    /// before the Unix epoch. A smaller number corresponds to an instant in
+    /// time further into the past.
+    pub fn from_millisecond(millis: i64) -> Result<Self> {
+        match jiff::Timestamp::from_millisecond(millis) {
+            Ok(t) => Ok(Timestamp(t)),
+            Err(err) => Err(Error::new(
+                ErrorKind::Unexpected,
+                format!("convert '{millis}' milliseconds into timestamp 
failed"),
+            )
+            .set_source(err)),
+        }
+    }
+
+    /// Creates a new instant in time from the number of seconds elapsed since
+    /// the Unix epoch.
+    ///
+    /// When `second` is negative, it corresponds to an instant in time before
+    /// the Unix epoch. A smaller number corresponds to an instant in time
+    /// further into the past.
+    pub fn from_second(second: i64) -> Result<Self> {
+        match jiff::Timestamp::from_second(second) {
+            Ok(t) => Ok(Timestamp(t)),
+            Err(err) => Err(Error::new(
+                ErrorKind::Unexpected,
+                format!("convert '{second}' seconds into timestamp failed"),
+            )
+            .set_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) -> Result<Timestamp> {
+        match jiff::fmt::rfc2822::parse(s) {
+            Ok(zoned) => Ok(Timestamp(zoned.timestamp())),
+            Err(err) => Err(Error::new(
+                ErrorKind::Unexpected,
+                format!("parse '{s}' into rfc2822 failed"),
+            )
+            .set_source(err)),
+        }
+    }
+
+    /// Parse the string format "2023-10-31 21:59:10.000000".
+    pub fn parse_datetime_utc(s: &str) -> Result<Timestamp> {
+        let dt = s.parse::<jiff::civil::DateTime>().map_err(|err| {
+            Error::new(
+                ErrorKind::Unexpected,
+                format!("parse '{s}' into datetime failed"),
+            )
+            .set_source(err)
+        })?;
+
+        let ts = jiff::tz::TimeZone::UTC.to_timestamp(dt).map_err(|err| {
+            Error::new(
+                ErrorKind::Unexpected,
+                format!("convert '{s}' into timestamp failed"),
+            )
+            .set_source(err)
+        })?;
+
+        Ok(Timestamp(ts))
+    }
+
+    /// Convert to inner `jiff::Timestamp` for compatibility.
+    ///
+    /// This method is provided for accessing the underlying `jiff::Timestamp`
+    /// when needed for interoperability with jiff-specific APIs.
+    pub fn into_inner(self) -> jiff::Timestamp {
+        self.0
+    }
+
+    /// Format the timestamp using `strftime` format string.
+    ///
+    /// Common formats:
+    /// - `"%Y-%m-%d"` - Date like `2022-03-01`
+    /// - `"%a, %d %b %Y %H:%M:%S GMT"` - HTTP date
+    ///
+    /// For full format documentation, see 
[jiff::fmt::strtime](https://docs.rs/jiff/latest/jiff/fmt/strtime/index.html)
+    pub fn strftime(self, format: &str) -> String {
+        self.0.strftime(format).to_string()
+    }
+}
+
+impl From<jiff::Timestamp> for Timestamp {
+    fn from(t: jiff::Timestamp) -> Self {
+        Timestamp(t)
+    }
+}
+
+impl From<Timestamp> for jiff::Timestamp {
+    fn from(t: Timestamp) -> Self {
+        t.0
+    }
+}
+
+impl TryFrom<SystemTime> for Timestamp {
+    type Error = Error;
+
+    fn try_from(t: SystemTime) -> Result<Self> {
+        jiff::Timestamp::try_from(t).map(Timestamp).map_err(|err| {
+            Error::new(ErrorKind::Unexpected, "input timestamp 
overflow").set_source(err)
+        })
+    }
+}
+
+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)
+    }
+}
+
+impl AddAssign<Duration> for Timestamp {
+    fn add_assign(&mut self, rhs: Duration) {
+        *self = *self + rhs
+    }
+}
+
+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)
+    }
+}
+
+impl SubAssign<Duration> for Timestamp {
+    fn sub_assign(&mut self, rhs: Duration) {
+        *self = *self - rhs
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn test_time() -> Timestamp {
+        Timestamp("2022-03-01T08:12:34Z".parse().unwrap())
+    }
+
+    #[test]
+    fn test_format_date() {
+        let t = test_time();
+        assert_eq!("20220301", t.format_date())
+    }
+
+    #[test]
+    fn test_format_iso8601() {
+        let t = test_time();
+        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", t.format_http_date())
+    }
+
+    #[test]
+    fn test_format_rfc3339() {
+        let t = test_time();
+        assert_eq!("2022-03-01T08:12:34Z", t.format_rfc3339_zulu())
+    }
+
+    #[test]
+    fn test_parse_rfc3339() {
+        let t = test_time();
+
+        for v in [
+            "2022-03-01T08:12:34Z",
+            "2022-03-01T08:12:34+00:00",
+            "2022-03-01T08:12:34.00+00:00",
+        ] {
+            assert_eq!(t, v.parse().expect("must be valid time"));
+        }
+    }
+
+    #[test]
+    fn test_parse_rfc2822() {
+        let s = "Sat, 29 Oct 1994 19:43:31 +0000";
+        let v = Timestamp::parse_rfc2822(s).unwrap();
+        assert_eq!("Sat, 29 Oct 1994 19:43:31 GMT", v.format_http_date());
+    }
+}
diff --git a/core/src/services/aliyun_drive/backend.rs 
b/core/src/services/aliyun_drive/backend.rs
index 828e49404..362aac6fe 100644
--- a/core/src/services/aliyun_drive/backend.rs
+++ b/core/src/services/aliyun_drive/backend.rs
@@ -22,7 +22,6 @@ use std::sync::Arc;
 use bytes::Buf;
 use http::Response;
 use http::StatusCode;
-use jiff::Timestamp;
 use log::debug;
 use tokio::sync::Mutex;
 
diff --git a/core/src/services/aliyun_drive/core.rs 
b/core/src/services/aliyun_drive/core.rs
index 3459c2ffc..eb20a7867 100644
--- a/core/src/services/aliyun_drive/core.rs
+++ b/core/src/services/aliyun_drive/core.rs
@@ -24,7 +24,6 @@ use http::Request;
 use http::Response;
 use http::header::HeaderValue;
 use http::header::{self};
-use jiff::Timestamp;
 use serde::Deserialize;
 use serde::Serialize;
 use tokio::sync::Mutex;
@@ -145,14 +144,15 @@ impl AliyunDriveCore {
                 access_token,
                 expire_at,
             ) => {
-                if *expire_at < Timestamp::now().as_second() || 
access_token.is_none() {
+                if *expire_at < Timestamp::now().into_inner().as_second() || 
access_token.is_none()
+                {
                     let res = self
                         .get_access_token(client_id, client_secret, 
refresh_token)
                         .await?;
                     let output: RefreshTokenResponse = 
serde_json::from_reader(res.reader())
                         .map_err(new_json_deserialize_error)?;
                     *access_token = Some(output.access_token);
-                    *expire_at = output.expires_in + 
Timestamp::now().as_second();
+                    *expire_at = output.expires_in + 
Timestamp::now().into_inner().as_second();
                     *refresh_token = output.refresh_token;
                 }
                 access_token.clone()
diff --git a/core/src/services/aliyun_drive/lister.rs 
b/core/src/services/aliyun_drive/lister.rs
index af61b79fe..8fa9e795a 100644
--- a/core/src/services/aliyun_drive/lister.rs
+++ b/core/src/services/aliyun_drive/lister.rs
@@ -27,7 +27,6 @@ use crate::Metadata;
 use crate::Result;
 use crate::raw::*;
 use bytes::Buf;
-use jiff::Timestamp;
 
 pub struct AliyunDriveLister {
     core: Arc<AliyunDriveCore>,
diff --git a/core/src/services/alluxio/core.rs 
b/core/src/services/alluxio/core.rs
index b9b0590e9..c670207d0 100644
--- a/core/src/services/alluxio/core.rs
+++ b/core/src/services/alluxio/core.rs
@@ -359,7 +359,7 @@ impl TryFrom<FileInfo> for Metadata {
         };
         metadata
             .set_content_length(file_info.length)
-            .set_last_modified(parse_datetime_from_timestamp_millis(
+            .set_last_modified(Timestamp::from_millisecond(
                 file_info.last_modification_time_ms,
             )?);
         Ok(metadata)
diff --git a/core/src/services/azblob/core.rs b/core/src/services/azblob/core.rs
index 9a215d433..42985f689 100644
--- a/core/src/services/azblob/core.rs
+++ b/core/src/services/azblob/core.rs
@@ -212,17 +212,11 @@ impl AzblobCore {
         }
 
         if let Some(if_modified_since) = args.if_modified_since() {
-            req = req.header(
-                IF_MODIFIED_SINCE,
-                format_datetime_into_http_date(if_modified_since),
-            );
+            req = req.header(IF_MODIFIED_SINCE, 
if_modified_since.format_http_date());
         }
 
         if let Some(if_unmodified_since) = args.if_unmodified_since() {
-            req = req.header(
-                IF_UNMODIFIED_SINCE,
-                format_datetime_into_http_date(if_unmodified_since),
-            );
+            req = req.header(IF_UNMODIFIED_SINCE, 
if_unmodified_since.format_http_date());
         }
 
         let req = req
diff --git a/core/src/services/azblob/lister.rs 
b/core/src/services/azblob/lister.rs
index f0ad7276c..2d2747125 100644
--- a/core/src/services/azblob/lister.rs
+++ b/core/src/services/azblob/lister.rs
@@ -94,7 +94,7 @@ impl oio::PageList for AzblobLister {
                 .with_content_length(object.properties.content_length)
                 .with_content_md5(object.properties.content_md5)
                 .with_content_type(object.properties.content_type)
-                .with_last_modified(parse_datetime_from_rfc2822(
+                .with_last_modified(Timestamp::parse_rfc2822(
                     object.properties.last_modified.as_str(),
                 )?);
 
diff --git a/core/src/services/azdls/lister.rs 
b/core/src/services/azdls/lister.rs
index 1296cb5b5..2e5744a81 100644
--- a/core/src/services/azdls/lister.rs
+++ b/core/src/services/azdls/lister.rs
@@ -93,7 +93,7 @@ impl oio::PageList for AzdlsLister {
                     Error::new(ErrorKind::Unexpected, "content length is not 
valid integer")
                         .set_source(err)
                 })?)
-                
.with_last_modified(parse_datetime_from_rfc2822(&object.last_modified)?);
+                
.with_last_modified(Timestamp::parse_rfc2822(&object.last_modified)?);
 
             let mut path = build_rel_path(&self.core.root, &object.name);
             if mode.is_dir() {
diff --git a/core/src/services/azfile/lister.rs 
b/core/src/services/azfile/lister.rs
index 5b59fafce..e52cbd0d6 100644
--- a/core/src/services/azfile/lister.rs
+++ b/core/src/services/azfile/lister.rs
@@ -77,7 +77,7 @@ impl oio::PageList for AzfileLister {
             let meta = Metadata::new(EntryMode::FILE)
                 .with_etag(file.properties.etag)
                 
.with_content_length(file.properties.content_length.unwrap_or(0))
-                
.with_last_modified(parse_datetime_from_rfc2822(&file.properties.last_modified)?);
+                
.with_last_modified(Timestamp::parse_rfc2822(&file.properties.last_modified)?);
             let path = self.path.clone().trim_start_matches('/').to_string() + 
&file.name;
             ctx.entries.push_back(oio::Entry::new(&path, meta));
         }
@@ -85,7 +85,7 @@ impl oio::PageList for AzfileLister {
         for dir in results.entries.directory {
             let meta = Metadata::new(EntryMode::DIR)
                 .with_etag(dir.properties.etag)
-                
.with_last_modified(parse_datetime_from_rfc2822(&dir.properties.last_modified)?);
+                
.with_last_modified(Timestamp::parse_rfc2822(&dir.properties.last_modified)?);
             let path = self.path.clone().trim_start_matches('/').to_string() + 
&dir.name + "/";
             ctx.entries.push_back(oio::Entry::new(&path, meta));
         }
diff --git a/core/src/services/b2/core.rs b/core/src/services/b2/core.rs
index e429a29b6..8c07612fb 100644
--- a/core/src/services/b2/core.rs
+++ b/core/src/services/b2/core.rs
@@ -25,7 +25,6 @@ use http::Request;
 use http::Response;
 use http::StatusCode;
 use http::header;
-use jiff::Timestamp;
 use serde::Deserialize;
 use serde::Serialize;
 use tokio::sync::RwLock;
diff --git a/core/src/services/cacache/backend.rs 
b/core/src/services/cacache/backend.rs
index a2b057e77..297c0dafb 100644
--- a/core/src/services/cacache/backend.rs
+++ b/core/src/services/cacache/backend.rs
@@ -18,7 +18,6 @@
 use crate::raw::*;
 use crate::services::CacacheConfig;
 use crate::*;
-use jiff::Timestamp;
 use std::fmt::Debug;
 use std::sync::Arc;
 
@@ -108,10 +107,8 @@ impl Access for CacacheAccessor {
                 let mut md = Metadata::new(EntryMode::FILE);
                 md.set_content_length(meta.size as u64);
                 // Convert u128 milliseconds to Timestamp
-                let millis = meta.time;
-                let secs = (millis / 1000) as i64;
-                let nanos = ((millis % 1000) * 1_000_000) as i32;
-                if let Ok(dt) = Timestamp::new(secs, nanos) {
+                let millis = meta.time as i64;
+                if let Ok(dt) = Timestamp::from_millisecond(millis) {
                     md.set_last_modified(dt);
                 }
                 Ok(RpStat::new(md))
diff --git a/core/src/services/cloudflare_kv/backend.rs 
b/core/src/services/cloudflare_kv/backend.rs
index 4820182d1..e0f5043a6 100644
--- a/core/src/services/cloudflare_kv/backend.rs
+++ b/core/src/services/cloudflare_kv/backend.rs
@@ -33,7 +33,6 @@ use crate::services::cloudflare_kv::writer::CloudflareWriter;
 use crate::*;
 use bytes::Buf;
 use http::StatusCode;
-use jiff::Timestamp;
 
 impl Configurator for CloudflareKvConfig {
     type Builder = CloudflareKvBuilder;
@@ -380,7 +379,7 @@ impl Access for CloudflareKvAccessor {
         })
         .with_etag(metadata.etag)
         .with_content_length(metadata.content_length as u64)
-        
.with_last_modified(parse_datetime_from_rfc3339(&metadata.last_modified)?);
+        .with_last_modified(metadata.last_modified.parse::<Timestamp>()?);
 
         Ok(RpStat::new(meta))
     }
diff --git a/core/src/services/cloudflare_kv/lister.rs 
b/core/src/services/cloudflare_kv/lister.rs
index bc09b7cda..1eeca9906 100644
--- a/core/src/services/cloudflare_kv/lister.rs
+++ b/core/src/services/cloudflare_kv/lister.rs
@@ -72,7 +72,7 @@ impl CloudflareKvLister {
             Metadata::new(EntryMode::FILE)
                 .with_etag(metadata.etag)
                 .with_content_length(metadata.content_length as u64)
-                
.with_last_modified(parse_datetime_from_rfc3339(&metadata.last_modified)?)
+                
.with_last_modified(metadata.last_modified.parse::<Timestamp>()?)
         };
 
         Ok(oio::Entry::new(&name, entry_metadata))
diff --git a/core/src/services/cloudflare_kv/writer.rs 
b/core/src/services/cloudflare_kv/writer.rs
index 1a3e422bc..c644611bd 100644
--- a/core/src/services/cloudflare_kv/writer.rs
+++ b/core/src/services/cloudflare_kv/writer.rs
@@ -23,7 +23,6 @@ use crate::raw::*;
 use crate::services::cloudflare_kv::model::CfKvMetadata;
 use crate::*;
 use http::StatusCode;
-use jiff::Timestamp;
 
 pub struct CloudflareWriter {
     core: Arc<CloudflareKvCore>,
@@ -56,8 +55,7 @@ impl oio::OneShotWrite for CloudflareWriter {
             StatusCode::OK => {
                 let mut metadata = Metadata::default();
                 metadata.set_etag(&cf_kv_metadata.etag);
-                metadata
-                    
.set_last_modified(parse_datetime_from_rfc3339(&cf_kv_metadata.last_modified)?);
+                
metadata.set_last_modified(cf_kv_metadata.last_modified.parse::<Timestamp>()?);
                 metadata.set_content_length(cf_kv_metadata.content_length as 
u64);
 
                 Ok(metadata)
diff --git a/core/src/services/compfs/backend.rs 
b/core/src/services/compfs/backend.rs
index 906fcab66..61e53928f 100644
--- a/core/src/services/compfs/backend.rs
+++ b/core/src/services/compfs/backend.rs
@@ -164,7 +164,7 @@ impl Access for CompfsBackend {
         } else {
             EntryMode::Unknown
         };
-        let last_mod = 
parse_datetime_from_system_time(meta.modified().map_err(new_std_io_error)?)?;
+        let last_mod = 
Timestamp::try_from(meta.modified().map_err(new_std_io_error)?)?;
         let ret = Metadata::new(mode)
             .with_last_modified(last_mod)
             .with_content_length(meta.len());
diff --git a/core/src/services/cos/core.rs b/core/src/services/cos/core.rs
index 547e8fa73..aaf878d39 100644
--- a/core/src/services/cos/core.rs
+++ b/core/src/services/cos/core.rs
@@ -163,17 +163,11 @@ impl CosCore {
         }
 
         if let Some(if_modified_since) = args.if_modified_since() {
-            req = req.header(
-                IF_MODIFIED_SINCE,
-                format_datetime_into_http_date(if_modified_since),
-            );
+            req = req.header(IF_MODIFIED_SINCE, 
if_modified_since.format_http_date());
         }
 
         if let Some(if_unmodified_since) = args.if_unmodified_since() {
-            req = req.header(
-                IF_UNMODIFIED_SINCE,
-                format_datetime_into_http_date(if_unmodified_since),
-            );
+            req = req.header(IF_UNMODIFIED_SINCE, 
if_unmodified_since.format_http_date());
         }
 
         let req = req.extension(Operation::Read);
diff --git a/core/src/services/cos/lister.rs b/core/src/services/cos/lister.rs
index a71c94f82..f8112ca64 100644
--- a/core/src/services/cos/lister.rs
+++ b/core/src/services/cos/lister.rs
@@ -200,9 +200,7 @@ impl oio::PageList for CosObjectVersionsLister {
             meta.set_version(&version_object.version_id);
             meta.set_is_current(version_object.is_latest);
             meta.set_content_length(version_object.size);
-            meta.set_last_modified(parse_datetime_from_rfc3339(
-                version_object.last_modified.as_str(),
-            )?);
+            
meta.set_last_modified(version_object.last_modified.parse::<Timestamp>()?);
             if let Some(etag) = version_object.etag {
                 meta.set_etag(&etag);
                 meta.set_content_md5(etag.trim_matches('"'));
@@ -223,9 +221,7 @@ impl oio::PageList for CosObjectVersionsLister {
                 meta.set_version(&delete_marker.version_id);
                 meta.set_is_deleted(true);
                 meta.set_is_current(delete_marker.is_latest);
-                meta.set_last_modified(parse_datetime_from_rfc3339(
-                    delete_marker.last_modified.as_str(),
-                )?);
+                
meta.set_last_modified(delete_marker.last_modified.parse::<Timestamp>()?);
 
                 let entry = oio::Entry::new(&path, meta);
                 ctx.entries.push_back(entry);
diff --git a/core/src/services/dashmap/writer.rs 
b/core/src/services/dashmap/writer.rs
index e641a33b4..54efe86cb 100644
--- a/core/src/services/dashmap/writer.rs
+++ b/core/src/services/dashmap/writer.rs
@@ -20,7 +20,7 @@ use std::time::SystemTime;
 
 use super::core::DashmapCore;
 use super::core::DashmapValue;
-use crate::raw::{OpWrite, oio, parse_datetime_from_system_time};
+use crate::raw::{OpWrite, Timestamp, oio};
 use crate::*;
 
 pub struct DashmapWriter {
@@ -54,7 +54,7 @@ impl oio::Write for DashmapWriter {
         let entry_mode = EntryMode::from_path(&self.path);
         let mut meta = Metadata::new(entry_mode);
         meta.set_content_length(content.len() as u64);
-        
meta.set_last_modified(parse_datetime_from_system_time(SystemTime::now())?);
+        meta.set_last_modified(Timestamp::try_from(SystemTime::now())?);
 
         if let Some(v) = self.op.content_type() {
             meta.set_content_type(v);
diff --git a/core/src/services/dbfs/backend.rs 
b/core/src/services/dbfs/backend.rs
index 2541dcfab..55414d3cc 100644
--- a/core/src/services/dbfs/backend.rs
+++ b/core/src/services/dbfs/backend.rs
@@ -195,7 +195,7 @@ impl Access for DbfsBackend {
                 let bs = resp.into_body();
                 let decoded_response: DbfsStatus =
                     
serde_json::from_reader(bs.reader()).map_err(new_json_deserialize_error)?;
-                meta.set_last_modified(parse_datetime_from_timestamp_millis(
+                meta.set_last_modified(Timestamp::from_millisecond(
                     decoded_response.modification_time,
                 )?);
                 match decoded_response.is_dir {
diff --git a/core/src/services/dbfs/lister.rs b/core/src/services/dbfs/lister.rs
index 2f5cc4cb9..18e3f3cb3 100644
--- a/core/src/services/dbfs/lister.rs
+++ b/core/src/services/dbfs/lister.rs
@@ -62,16 +62,12 @@ impl oio::PageList for DbfsLister {
                 true => {
                     let normalized_path = format!("{}/", &status.path);
                     let mut meta = Metadata::new(EntryMode::DIR);
-                    
meta.set_last_modified(parse_datetime_from_timestamp_millis(
-                        status.modification_time,
-                    )?);
+                    
meta.set_last_modified(Timestamp::from_millisecond(status.modification_time)?);
                     oio::Entry::new(&normalized_path, meta)
                 }
                 false => {
                     let mut meta = Metadata::new(EntryMode::FILE);
-                    
meta.set_last_modified(parse_datetime_from_timestamp_millis(
-                        status.modification_time,
-                    )?);
+                    
meta.set_last_modified(Timestamp::from_millisecond(status.modification_time)?);
                     meta.set_content_length(status.file_size as u64);
                     oio::Entry::new(&status.path, meta)
                 }
diff --git a/core/src/services/dropbox/backend.rs 
b/core/src/services/dropbox/backend.rs
index 755bd4119..5b41dca85 100644
--- a/core/src/services/dropbox/backend.rs
+++ b/core/src/services/dropbox/backend.rs
@@ -87,7 +87,7 @@ impl Access for DropboxBackend {
                 // FYI: 
https://www.dropbox.com/developers/documentation/http/documentation#files-get_metadata
                 if entry_mode == EntryMode::FILE {
                     let date_utc_last_modified =
-                        
parse_datetime_from_rfc3339(&decoded_response.client_modified)?;
+                        decoded_response.client_modified.parse::<Timestamp>()?;
                     metadata.set_last_modified(date_utc_last_modified);
 
                     if let Some(size) = decoded_response.size {
diff --git a/core/src/services/dropbox/builder.rs 
b/core/src/services/dropbox/builder.rs
index 549459f6a..1b8e794ad 100644
--- a/core/src/services/dropbox/builder.rs
+++ b/core/src/services/dropbox/builder.rs
@@ -15,7 +15,6 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use jiff::Timestamp;
 use std::fmt::Debug;
 use std::fmt::Formatter;
 use std::sync::Arc;
diff --git a/core/src/services/dropbox/core.rs 
b/core/src/services/dropbox/core.rs
index b6c59978a..3972b9306 100644
--- a/core/src/services/dropbox/core.rs
+++ b/core/src/services/dropbox/core.rs
@@ -23,7 +23,6 @@ use http::StatusCode;
 use http::header;
 use http::header::CONTENT_LENGTH;
 use http::header::CONTENT_TYPE;
-use jiff::Timestamp;
 use serde::Deserialize;
 use serde::Serialize;
 use std::default::Default;
diff --git a/core/src/services/dropbox/lister.rs 
b/core/src/services/dropbox/lister.rs
index 4b07da427..3dc70c91c 100644
--- a/core/src/services/dropbox/lister.rs
+++ b/core/src/services/dropbox/lister.rs
@@ -95,7 +95,7 @@ impl oio::PageList for DropboxLister {
 
             // The behavior here aligns with Dropbox's stat function.
             if entry_mode == EntryMode::FILE {
-                let date_utc_last_modified = 
parse_datetime_from_rfc3339(&entry.client_modified)?;
+                let date_utc_last_modified = 
entry.client_modified.parse::<Timestamp>()?;
                 meta.set_last_modified(date_utc_last_modified);
 
                 if let Some(size) = entry.size {
diff --git a/core/src/services/fs/core.rs b/core/src/services/fs/core.rs
index 46d731eef..0655e4226 100644
--- a/core/src/services/fs/core.rs
+++ b/core/src/services/fs/core.rs
@@ -81,7 +81,7 @@ impl FsCore {
         };
         let m = Metadata::new(mode)
             .with_content_length(meta.len())
-            .with_last_modified(parse_datetime_from_system_time(
+            .with_last_modified(Timestamp::try_from(
                 meta.modified().map_err(new_std_io_error)?,
             )?);
         Ok(m)
diff --git a/core/src/services/fs/writer.rs b/core/src/services/fs/writer.rs
index 38c4c2f3e..87374e7b2 100644
--- a/core/src/services/fs/writer.rs
+++ b/core/src/services/fs/writer.rs
@@ -107,7 +107,7 @@ impl oio::Write for FsWriter {
         let file_meta = self.f.metadata().await.map_err(new_std_io_error)?;
         let meta = Metadata::new(EntryMode::FILE)
             .with_content_length(file_meta.len())
-            .with_last_modified(parse_datetime_from_system_time(
+            .with_last_modified(Timestamp::try_from(
                 file_meta.modified().map_err(new_std_io_error)?,
             )?);
         Ok(meta)
@@ -183,7 +183,7 @@ impl oio::PositionWrite for FsWriter {
         };
         let meta = Metadata::new(mode)
             .with_content_length(file_meta.len())
-            .with_last_modified(parse_datetime_from_system_time(
+            .with_last_modified(Timestamp::try_from(
                 file_meta.modified().map_err(new_std_io_error)?,
             )?);
         Ok(meta)
diff --git a/core/src/services/ftp/backend.rs b/core/src/services/ftp/backend.rs
index 660e6e873..ff7bf662a 100644
--- a/core/src/services/ftp/backend.rs
+++ b/core/src/services/ftp/backend.rs
@@ -258,7 +258,7 @@ impl Access for FtpBackend {
 
         let mut meta = Metadata::new(mode);
         meta.set_content_length(file.size() as u64);
-        
meta.set_last_modified(parse_datetime_from_system_time(file.modified())?);
+        meta.set_last_modified(Timestamp::try_from(file.modified())?);
 
         Ok(RpStat::new(meta))
     }
diff --git a/core/src/services/ftp/lister.rs b/core/src/services/ftp/lister.rs
index a7fd77085..2e57e8abe 100644
--- a/core/src/services/ftp/lister.rs
+++ b/core/src/services/ftp/lister.rs
@@ -57,7 +57,7 @@ impl oio::List for FtpLister {
             Metadata::new(EntryMode::Unknown)
         };
         meta.set_content_length(de.size() as u64);
-        
meta.set_last_modified(parse_datetime_from_system_time(de.modified())?);
+        meta.set_last_modified(Timestamp::try_from(de.modified())?);
 
         let entry = if de.is_file() {
             oio::Entry::new(&path, meta)
diff --git a/core/src/services/gcs/core.rs b/core/src/services/gcs/core.rs
index 4ad063ac5..2dc1594ab 100644
--- a/core/src/services/gcs/core.rs
+++ b/core/src/services/gcs/core.rs
@@ -231,17 +231,11 @@ impl GcsCore {
         }
 
         if let Some(if_modified_since) = args.if_modified_since() {
-            req = req.header(
-                IF_MODIFIED_SINCE,
-                format_datetime_into_http_date(if_modified_since),
-            );
+            req = req.header(IF_MODIFIED_SINCE, 
if_modified_since.format_http_date());
         }
 
         if let Some(if_unmodified_since) = args.if_unmodified_since() {
-            req = req.header(
-                IF_UNMODIFIED_SINCE,
-                format_datetime_into_http_date(if_unmodified_since),
-            );
+            req = req.header(IF_UNMODIFIED_SINCE, 
if_unmodified_since.format_http_date());
         }
 
         let req = req.extension(Operation::Read);
@@ -741,7 +735,7 @@ impl GcsCore {
             m.set_version(&meta.generation);
         }
 
-        m.set_last_modified(parse_datetime_from_rfc3339(&meta.updated)?);
+        m.set_last_modified(meta.updated.parse::<Timestamp>()?);
 
         if !meta.metadata.is_empty() {
             m = m.with_user_metadata(meta.metadata);
@@ -921,7 +915,8 @@ mod tests {
         assert_eq!(
             meta.last_modified(),
             Some(
-                parse_datetime_from_rfc3339("2022-08-15T11:33:34.866Z")
+                "2022-08-15T11:33:34.866Z"
+                    .parse::<Timestamp>()
                     .expect("parse date should not fail")
             )
         );
diff --git a/core/src/services/gcs/lister.rs b/core/src/services/gcs/lister.rs
index cd66e964f..2b2205960 100644
--- a/core/src/services/gcs/lister.rs
+++ b/core/src/services/gcs/lister.rs
@@ -124,7 +124,7 @@ impl oio::PageList for GcsLister {
                 meta.set_content_type(&object.content_type);
             }
 
-            
meta.set_last_modified(parse_datetime_from_rfc3339(object.updated.as_str())?);
+            meta.set_last_modified(object.updated.parse::<Timestamp>()?);
 
             let de = oio::Entry::with(path, meta);
 
diff --git a/core/src/services/gdrive/backend.rs 
b/core/src/services/gdrive/backend.rs
index df5bc659c..1efe3f969 100644
--- a/core/src/services/gdrive/backend.rs
+++ b/core/src/services/gdrive/backend.rs
@@ -29,7 +29,6 @@ use crate::*;
 use bytes::Buf;
 use http::Response;
 use http::StatusCode;
-use jiff::Timestamp;
 
 #[derive(Clone, Debug)]
 pub struct GdriveBackend {
diff --git a/core/src/services/gdrive/builder.rs 
b/core/src/services/gdrive/builder.rs
index dc5a0946b..e6425e4fc 100644
--- a/core/src/services/gdrive/builder.rs
+++ b/core/src/services/gdrive/builder.rs
@@ -15,7 +15,6 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use jiff::Timestamp;
 use log::debug;
 use std::fmt::Debug;
 use std::fmt::Formatter;
@@ -32,6 +31,7 @@ use crate::raw::Access;
 use crate::raw::AccessorInfo;
 use crate::raw::HttpClient;
 use crate::raw::PathCacher;
+use crate::raw::Timestamp;
 use crate::raw::normalize_root;
 use crate::services::GdriveConfig;
 use crate::*;
diff --git a/core/src/services/gdrive/core.rs b/core/src/services/gdrive/core.rs
index 82354dd67..94b7e340f 100644
--- a/core/src/services/gdrive/core.rs
+++ b/core/src/services/gdrive/core.rs
@@ -22,7 +22,6 @@ use http::Request;
 use http::Response;
 use http::StatusCode;
 use http::header;
-use jiff::Timestamp;
 use serde::Deserialize;
 use serde_json::json;
 use std::fmt::Debug;
diff --git a/core/src/services/github/core.rs b/core/src/services/github/core.rs
index 944cd0fd9..f88e5ec24 100644
--- a/core/src/services/github/core.rs
+++ b/core/src/services/github/core.rs
@@ -27,7 +27,6 @@ use http::Response;
 use http::StatusCode;
 use http::header;
 use http::request;
-use jiff::Timestamp;
 use serde::Deserialize;
 use serde::Serialize;
 
diff --git a/core/src/services/hdfs/backend.rs 
b/core/src/services/hdfs/backend.rs
index 22555cee2..14613cfa2 100644
--- a/core/src/services/hdfs/backend.rs
+++ b/core/src/services/hdfs/backend.rs
@@ -249,7 +249,7 @@ impl Access for HdfsBackend {
         };
         let mut m = Metadata::new(mode);
         m.set_content_length(meta.len());
-        m.set_last_modified(parse_datetime_from_system_time(meta.modified())?);
+        m.set_last_modified(Timestamp::try_from(meta.modified())?);
 
         Ok(RpStat::new(m))
     }
diff --git a/core/src/services/hdfs/lister.rs b/core/src/services/hdfs/lister.rs
index 7d83ead57..84bea9340 100644
--- a/core/src/services/hdfs/lister.rs
+++ b/core/src/services/hdfs/lister.rs
@@ -56,7 +56,7 @@ impl oio::List for HdfsLister {
         let entry = if de.is_file() {
             let meta = Metadata::new(EntryMode::FILE)
                 .with_content_length(de.len())
-                
.with_last_modified(parse_datetime_from_system_time(de.modified())?);
+                .with_last_modified(Timestamp::try_from(de.modified())?);
             oio::Entry::new(&path, meta)
         } else if de.is_dir() {
             // Make sure we are returning the correct path.
diff --git a/core/src/services/hdfs_native/backend.rs 
b/core/src/services/hdfs_native/backend.rs
index 39c41824d..0848c3059 100644
--- a/core/src/services/hdfs_native/backend.rs
+++ b/core/src/services/hdfs_native/backend.rs
@@ -205,7 +205,7 @@ impl Access for HdfsNativeBackend {
 
         let mut metadata = Metadata::new(mode);
         metadata
-            .set_last_modified(parse_datetime_from_timestamp_millis(
+            .set_last_modified(Timestamp::from_millisecond(
                 status.modification_time as i64,
             )?)
             .set_content_length(status.length as u64);
diff --git a/core/src/services/hdfs_native/lister.rs 
b/core/src/services/hdfs_native/lister.rs
index af18b658d..b7583b024 100644
--- a/core/src/services/hdfs_native/lister.rs
+++ b/core/src/services/hdfs_native/lister.rs
@@ -20,9 +20,9 @@ use hdfs_native::client::ListStatusIterator;
 use crate::EntryMode;
 use crate::Metadata;
 use crate::Result;
+use crate::raw::Timestamp;
 use crate::raw::build_rel_path;
 use crate::raw::oio;
-use crate::raw::parse_datetime_from_timestamp_millis;
 use crate::services::hdfs_native::error::parse_hdfs_error;
 
 pub struct HdfsNativeLister {
@@ -67,7 +67,7 @@ impl oio::List for HdfsNativeLister {
                 } else {
                     let meta = Metadata::new(EntryMode::FILE)
                         .with_content_length(status.length as u64)
-                        
.with_last_modified(parse_datetime_from_timestamp_millis(
+                        .with_last_modified(Timestamp::from_millisecond(
                             status.modification_time as i64,
                         )?);
                     oio::Entry::new(&path, meta)
diff --git a/core/src/services/huggingface/backend.rs 
b/core/src/services/huggingface/backend.rs
index 4044df15f..17817b2b5 100644
--- a/core/src/services/huggingface/backend.rs
+++ b/core/src/services/huggingface/backend.rs
@@ -234,9 +234,7 @@ impl Access for HuggingfaceBackend {
                 // NOTE: if the file is not found, the server will return 200 
with an empty array
                 if let Some(status) = decoded_response.first() {
                     if let Some(commit_info) = status.last_commit.as_ref() {
-                        meta.set_last_modified(parse_datetime_from_rfc3339(
-                            commit_info.date.as_str(),
-                        )?);
+                        
meta.set_last_modified(commit_info.date.parse::<Timestamp>()?);
                     }
 
                     meta.set_content_length(status.size);
diff --git a/core/src/services/huggingface/lister.rs 
b/core/src/services/huggingface/lister.rs
index 862c67236..b8d768eea 100644
--- a/core/src/services/huggingface/lister.rs
+++ b/core/src/services/huggingface/lister.rs
@@ -67,7 +67,7 @@ impl oio::PageList for HuggingfaceLister {
             let mut meta = Metadata::new(entry_type);
 
             if let Some(commit_info) = status.last_commit.as_ref() {
-                
meta.set_last_modified(parse_datetime_from_rfc3339(commit_info.date.as_str())?);
+                meta.set_last_modified(commit_info.date.parse::<Timestamp>()?);
             }
 
             if entry_type == EntryMode::FILE {
diff --git a/core/src/services/koofr/backend.rs 
b/core/src/services/koofr/backend.rs
index a56cf7b85..3984bec6f 100644
--- a/core/src/services/koofr/backend.rs
+++ b/core/src/services/koofr/backend.rs
@@ -265,7 +265,7 @@ impl Access for KoofrBackend {
 
                 md.set_content_length(file.size)
                     .set_content_type(&file.content_type)
-                    
.set_last_modified(parse_datetime_from_timestamp_millis(file.modified)?);
+                    
.set_last_modified(Timestamp::from_millisecond(file.modified)?);
 
                 Ok(RpStat::new(md))
             }
diff --git a/core/src/services/koofr/lister.rs 
b/core/src/services/koofr/lister.rs
index 88642aa78..1e00b043e 100644
--- a/core/src/services/koofr/lister.rs
+++ b/core/src/services/koofr/lister.rs
@@ -74,7 +74,7 @@ impl oio::PageList for KoofrLister {
                 let m = Metadata::new(EntryMode::FILE)
                     .with_content_length(file.size)
                     .with_content_type(file.content_type)
-                    
.with_last_modified(parse_datetime_from_timestamp_millis(file.modified)?);
+                    
.with_last_modified(Timestamp::from_millisecond(file.modified)?);
                 Entry::new(&path, m)
             };
 
diff --git a/core/src/services/lakefs/backend.rs 
b/core/src/services/lakefs/backend.rs
index f4802e843..068579963 100644
--- a/core/src/services/lakefs/backend.rs
+++ b/core/src/services/lakefs/backend.rs
@@ -22,7 +22,6 @@ use std::sync::Arc;
 use bytes::Buf;
 use http::Response;
 use http::StatusCode;
-use jiff::Timestamp;
 use log::debug;
 
 use super::DEFAULT_SCHEME;
diff --git a/core/src/services/lakefs/lister.rs 
b/core/src/services/lakefs/lister.rs
index e73a26473..fe49f1529 100644
--- a/core/src/services/lakefs/lister.rs
+++ b/core/src/services/lakefs/lister.rs
@@ -23,7 +23,6 @@ use super::error::parse_error;
 use crate::raw::*;
 use crate::*;
 use bytes::Buf;
-use jiff::Timestamp;
 
 pub struct LakefsLister {
     core: Arc<LakefsCore>,
diff --git a/core/src/services/mini_moka/writer.rs 
b/core/src/services/mini_moka/writer.rs
index 5e5c12b13..aafdacfec 100644
--- a/core/src/services/mini_moka/writer.rs
+++ b/core/src/services/mini_moka/writer.rs
@@ -19,7 +19,6 @@ use super::core::{MiniMokaCore, MiniMokaValue};
 use crate::raw::oio;
 use crate::raw::*;
 use crate::*;
-use jiff::Timestamp;
 use std::sync::Arc;
 
 pub struct MiniMokaWriter {
diff --git a/core/src/services/monoiofs/backend.rs 
b/core/src/services/monoiofs/backend.rs
index 217714217..9332b247e 100644
--- a/core/src/services/monoiofs/backend.rs
+++ b/core/src/services/monoiofs/backend.rs
@@ -124,7 +124,7 @@ impl Access for MonoiofsBackend {
         };
         let m = Metadata::new(mode)
             .with_content_length(meta.len())
-            .with_last_modified(parse_datetime_from_system_time(
+            .with_last_modified(Timestamp::try_from(
                 meta.modified().map_err(new_std_io_error)?,
             )?);
         Ok(RpStat::new(m))
diff --git a/core/src/services/monoiofs/writer.rs 
b/core/src/services/monoiofs/writer.rs
index e4172e561..ab36e2701 100644
--- a/core/src/services/monoiofs/writer.rs
+++ b/core/src/services/monoiofs/writer.rs
@@ -170,7 +170,7 @@ impl oio::Write for MonoiofsWriter {
         };
         let meta = Metadata::new(mode)
             .with_content_length(file_meta.len())
-            .with_last_modified(parse_datetime_from_system_time(
+            .with_last_modified(Timestamp::try_from(
                 file_meta.modified().map_err(new_std_io_error)?,
             )?);
         Ok(meta)
diff --git a/core/src/services/onedrive/builder.rs 
b/core/src/services/onedrive/builder.rs
index 35be2cbbb..7dd856548 100644
--- a/core/src/services/onedrive/builder.rs
+++ b/core/src/services/onedrive/builder.rs
@@ -15,7 +15,6 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use jiff::Timestamp;
 use log::debug;
 use services::onedrive::core::OneDriveCore;
 use services::onedrive::core::OneDriveSigner;
@@ -30,6 +29,7 @@ use crate::Scheme;
 use crate::raw::Access;
 use crate::raw::AccessorInfo;
 use crate::raw::HttpClient;
+use crate::raw::Timestamp;
 use crate::raw::normalize_root;
 use crate::services::OnedriveConfig;
 use crate::*;
diff --git a/core/src/services/onedrive/core.rs 
b/core/src/services/onedrive/core.rs
index 07cb7746c..359156109 100644
--- a/core/src/services/onedrive/core.rs
+++ b/core/src/services/onedrive/core.rs
@@ -26,7 +26,6 @@ use http::Request;
 use http::Response;
 use http::StatusCode;
 use http::header;
-use jiff::Timestamp;
 use tokio::sync::Mutex;
 
 use super::error::parse_error;
@@ -213,7 +212,7 @@ impl OneDriveCore {
         }
 
         let last_modified = decoded_response.last_modified_date_time;
-        let date_utc_last_modified = 
parse_datetime_from_rfc3339(&last_modified)?;
+        let date_utc_last_modified = last_modified.parse::<Timestamp>()?;
         meta.set_last_modified(date_utc_last_modified);
 
         Ok(meta)
diff --git a/core/src/services/onedrive/lister.rs 
b/core/src/services/onedrive/lister.rs
index 8651f8f3f..86454e2a2 100644
--- a/core/src/services/onedrive/lister.rs
+++ b/core/src/services/onedrive/lister.rs
@@ -126,8 +126,7 @@ impl oio::PageList for OneDriveLister {
             let mut meta = Metadata::new(entry_mode)
                 .with_etag(drive_item.e_tag)
                 .with_content_length(drive_item.size.max(0) as u64);
-            let last_modified =
-                
parse_datetime_from_rfc3339(drive_item.last_modified_date_time.as_str())?;
+            let last_modified = 
drive_item.last_modified_date_time.parse::<Timestamp>()?;
             meta.set_last_modified(last_modified);
 
             // When listing a directory with `$expand=versions`, OneDrive 
returns 400 "Operation not supported".
diff --git a/core/src/services/onedrive/writer.rs 
b/core/src/services/onedrive/writer.rs
index 7c87a817d..e986b0b23 100644
--- a/core/src/services/onedrive/writer.rs
+++ b/core/src/services/onedrive/writer.rs
@@ -80,7 +80,7 @@ impl OneDriveWriter {
                     .with_content_length(item.size.max(0) as u64);
 
                 let last_modified = item.last_modified_date_time;
-                let date_utc_last_modified = 
parse_datetime_from_rfc3339(&last_modified)?;
+                let date_utc_last_modified = 
last_modified.parse::<Timestamp>()?;
                 meta.set_last_modified(date_utc_last_modified);
 
                 Ok(meta)
@@ -135,7 +135,7 @@ impl OneDriveWriter {
                         .with_content_length(item.size.max(0) as u64);
 
                     let last_modified = item.last_modified_date_time;
-                    let date_utc_last_modified = 
parse_datetime_from_rfc3339(&last_modified)?;
+                    let date_utc_last_modified = 
last_modified.parse::<Timestamp>()?;
                     meta.set_last_modified(date_utc_last_modified);
                     return Ok(meta);
                 }
diff --git a/core/src/services/oss/core.rs b/core/src/services/oss/core.rs
index b36ea2f9f..c2bf4ebca 100644
--- a/core/src/services/oss/core.rs
+++ b/core/src/services/oss/core.rs
@@ -351,17 +351,11 @@ impl OssCore {
         }
 
         if let Some(if_modified_since) = args.if_modified_since() {
-            req = req.header(
-                IF_MODIFIED_SINCE,
-                format_datetime_into_http_date(if_modified_since),
-            );
+            req = req.header(IF_MODIFIED_SINCE, 
if_modified_since.format_http_date());
         }
 
         if let Some(if_unmodified_since) = args.if_unmodified_since() {
-            req = req.header(
-                IF_UNMODIFIED_SINCE,
-                format_datetime_into_http_date(if_unmodified_since),
-            );
+            req = req.header(IF_UNMODIFIED_SINCE, 
if_unmodified_since.format_http_date());
         }
 
         let req = req.extension(Operation::Read);
diff --git a/core/src/services/oss/lister.rs b/core/src/services/oss/lister.rs
index 286147a00..f6c312cbf 100644
--- a/core/src/services/oss/lister.rs
+++ b/core/src/services/oss/lister.rs
@@ -109,7 +109,7 @@ impl oio::PageList for OssLister {
             meta.set_etag(&object.etag);
             meta.set_content_md5(object.etag.trim_matches('"'));
             meta.set_content_length(object.size);
-            
meta.set_last_modified(parse_datetime_from_rfc3339(object.last_modified.as_str())?);
+            meta.set_last_modified(object.last_modified.parse::<Timestamp>()?);
 
             let de = oio::Entry::with(path, meta);
             ctx.entries.push_back(de);
@@ -219,9 +219,7 @@ impl oio::PageList for OssObjectVersionsLister {
             meta.set_version(&version_object.version_id);
             meta.set_is_current(version_object.is_latest);
             meta.set_content_length(version_object.size);
-            meta.set_last_modified(parse_datetime_from_rfc3339(
-                version_object.last_modified.as_str(),
-            )?);
+            
meta.set_last_modified(version_object.last_modified.parse::<Timestamp>()?);
             if let Some(etag) = version_object.etag {
                 meta.set_etag(&etag);
                 meta.set_content_md5(etag.trim_matches('"'));
@@ -242,9 +240,7 @@ impl oio::PageList for OssObjectVersionsLister {
                 meta.set_version(&delete_marker.version_id);
                 meta.set_is_deleted(true);
                 meta.set_is_current(delete_marker.is_latest);
-                meta.set_last_modified(parse_datetime_from_rfc3339(
-                    delete_marker.last_modified.as_str(),
-                )?);
+                
meta.set_last_modified(delete_marker.last_modified.parse::<Timestamp>()?);
 
                 let entry = oio::Entry::new(&path, meta);
                 ctx.entries.push_back(entry);
diff --git a/core/src/services/pcloud/core.rs b/core/src/services/pcloud/core.rs
index 2f75a7a59..b6cf55438 100644
--- a/core/src/services/pcloud/core.rs
+++ b/core/src/services/pcloud/core.rs
@@ -404,7 +404,7 @@ pub(super) fn parse_stat_metadata(content: StatMetadata) -> 
Result<Metadata> {
         md.set_content_length(size);
     }
 
-    md.set_last_modified(parse_datetime_from_rfc2822(&content.modified)?);
+    md.set_last_modified(Timestamp::parse_rfc2822(&content.modified)?);
 
     Ok(md)
 }
@@ -420,7 +420,7 @@ pub(super) fn parse_list_metadata(content: ListMetadata) -> 
Result<Metadata> {
         md.set_content_length(size);
     }
 
-    md.set_last_modified(parse_datetime_from_rfc2822(&content.modified)?);
+    md.set_last_modified(Timestamp::parse_rfc2822(&content.modified)?);
 
     Ok(md)
 }
diff --git a/core/src/services/s3/core.rs b/core/src/services/s3/core.rs
index 22e7d1f57..06232589a 100644
--- a/core/src/services/s3/core.rs
+++ b/core/src/services/s3/core.rs
@@ -412,16 +412,10 @@ impl S3Core {
         }
 
         if let Some(if_modified_since) = args.if_modified_since() {
-            req = req.header(
-                IF_MODIFIED_SINCE,
-                format_datetime_into_http_date(if_modified_since),
-            );
+            req = req.header(IF_MODIFIED_SINCE, 
if_modified_since.format_http_date());
         }
         if let Some(if_unmodified_since) = args.if_unmodified_since() {
-            req = req.header(
-                IF_UNMODIFIED_SINCE,
-                format_datetime_into_http_date(if_unmodified_since),
-            );
+            req = req.header(IF_UNMODIFIED_SINCE, 
if_unmodified_since.format_http_date());
         }
 
         // Set request payer header if enabled.
@@ -495,17 +489,11 @@ impl S3Core {
         }
 
         if let Some(if_modified_since) = args.if_modified_since() {
-            req = req.header(
-                IF_MODIFIED_SINCE,
-                format_datetime_into_http_date(if_modified_since),
-            );
+            req = req.header(IF_MODIFIED_SINCE, 
if_modified_since.format_http_date());
         }
 
         if let Some(if_unmodified_since) = args.if_unmodified_since() {
-            req = req.header(
-                IF_UNMODIFIED_SINCE,
-                format_datetime_into_http_date(if_unmodified_since),
-            );
+            req = req.header(IF_UNMODIFIED_SINCE, 
if_unmodified_since.format_http_date());
         }
 
         // Set request payer header if enabled.
diff --git a/core/src/services/s3/lister.rs b/core/src/services/s3/lister.rs
index 6ce7e6ac0..ae15788ff 100644
--- a/core/src/services/s3/lister.rs
+++ b/core/src/services/s3/lister.rs
@@ -148,7 +148,7 @@ impl oio::PageList for S3ListerV1 {
 
             // object.last_modified provides more precise time that contains
             // nanosecond, let's trim them.
-            
meta.set_last_modified(parse_datetime_from_rfc3339(object.last_modified.as_str())?);
+            meta.set_last_modified(object.last_modified.parse::<Timestamp>()?);
 
             let de = oio::Entry::with(path, meta);
             ctx.entries.push_back(de);
@@ -258,7 +258,7 @@ impl oio::PageList for S3ListerV2 {
 
             // object.last_modified provides more precise time that contains
             // nanosecond, let's trim them.
-            
meta.set_last_modified(parse_datetime_from_rfc3339(object.last_modified.as_str())?);
+            meta.set_last_modified(object.last_modified.parse::<Timestamp>()?);
 
             let de = oio::Entry::with(path, meta);
             ctx.entries.push_back(de);
@@ -368,9 +368,8 @@ impl oio::PageList for S3ObjectVersionsLister {
             meta.set_version(&version_object.version_id);
             meta.set_is_current(version_object.is_latest);
             meta.set_content_length(version_object.size);
-            meta.set_last_modified(parse_datetime_from_rfc3339(
-                version_object.last_modified.as_str(),
-            )?);
+            
meta.set_last_modified(version_object.last_modified.parse::<Timestamp>()?);
+
             if let Some(etag) = version_object.etag {
                 meta.set_etag(&etag);
                 meta.set_content_md5(etag.trim_matches('"'));
@@ -391,9 +390,7 @@ impl oio::PageList for S3ObjectVersionsLister {
                 meta.set_version(&delete_marker.version_id);
                 meta.set_is_deleted(true);
                 meta.set_is_current(delete_marker.is_latest);
-                meta.set_last_modified(parse_datetime_from_rfc3339(
-                    delete_marker.last_modified.as_str(),
-                )?);
+                
meta.set_last_modified(delete_marker.last_modified.parse::<Timestamp>()?);
 
                 let entry = oio::Entry::new(&path, meta);
                 ctx.entries.push_back(entry);
diff --git a/core/src/services/seafile/core.rs 
b/core/src/services/seafile/core.rs
index e90a80dcf..286cdc9a5 100644
--- a/core/src/services/seafile/core.rs
+++ b/core/src/services/seafile/core.rs
@@ -427,7 +427,7 @@ pub struct DirDetail {
 pub fn parse_dir_detail(dir_detail: DirDetail) -> Result<Metadata> {
     let mut md = Metadata::new(EntryMode::DIR);
 
-    md.set_last_modified(parse_datetime_from_rfc3339(&dir_detail.mtime)?);
+    md.set_last_modified(dir_detail.mtime.parse::<Timestamp>()?);
 
     Ok(md)
 }
@@ -436,7 +436,7 @@ pub fn parse_file_detail(file_detail: FileDetail) -> 
Result<Metadata> {
     let mut md = Metadata::new(EntryMode::FILE);
 
     md.set_content_length(file_detail.size);
-    
md.set_last_modified(parse_datetime_from_rfc3339(&file_detail.last_modified)?);
+    md.set_last_modified(file_detail.last_modified.parse::<Timestamp>()?);
 
     Ok(md)
 }
diff --git a/core/src/services/seafile/lister.rs 
b/core/src/services/seafile/lister.rs
index e1720cde9..6f24f3389 100644
--- a/core/src/services/seafile/lister.rs
+++ b/core/src/services/seafile/lister.rs
@@ -57,7 +57,7 @@ impl oio::PageList for SeafileLister {
 
                         let entry = if info.type_field == "file" {
                             let meta = Metadata::new(EntryMode::FILE)
-                                
.with_last_modified(parse_datetime_from_timestamp(info.mtime)?)
+                                
.with_last_modified(Timestamp::from_second(info.mtime)?)
                                 .with_content_length(info.size.unwrap_or(0));
                             Entry::new(&rel_path, meta)
                         } else {
diff --git a/core/src/services/sftp/utils.rs b/core/src/services/sftp/utils.rs
index 96f9fa9a1..98e15bfbf 100644
--- a/core/src/services/sftp/utils.rs
+++ b/core/src/services/sftp/utils.rs
@@ -19,7 +19,7 @@ use openssh_sftp_client::metadata::MetaData as SftpMeta;
 
 use crate::EntryMode;
 use crate::Metadata;
-use crate::raw::parse_datetime_from_system_time;
+use crate::raw::Timestamp;
 
 /// REMOVE ME: we should not implement `From<SftpMeta> for Metadata`.
 impl From<SftpMeta> for Metadata {
@@ -44,7 +44,7 @@ impl From<SftpMeta> for Metadata {
         }
 
         if let Some(modified) = meta.modified() {
-            if let Ok(m) = 
parse_datetime_from_system_time(modified.as_system_time()) {
+            if let Ok(m) = Timestamp::try_from(modified.as_system_time()) {
                 metadata.set_last_modified(m);
             }
         }
diff --git a/core/src/services/swift/lister.rs 
b/core/src/services/swift/lister.rs
index adf40b917..6cbde6223 100644
--- a/core/src/services/swift/lister.rs
+++ b/core/src/services/swift/lister.rs
@@ -103,7 +103,7 @@ impl oio::PageList for SwiftLister {
                     if !last_modified.ends_with('Z') {
                         last_modified.push('Z');
                     }
-                    
meta.set_last_modified(parse_datetime_from_rfc3339(last_modified.as_str())?);
+                    
meta.set_last_modified(last_modified.parse::<Timestamp>()?);
 
                     if let Some(content_type) = content_type {
                         meta.set_content_type(content_type.as_str());
diff --git a/core/src/services/upyun/core.rs b/core/src/services/upyun/core.rs
index 881fdf2d5..2637a61c8 100644
--- a/core/src/services/upyun/core.rs
+++ b/core/src/services/upyun/core.rs
@@ -26,7 +26,6 @@ use http::HeaderMap;
 use http::Request;
 use http::Response;
 use http::header;
-use jiff::Timestamp;
 use md5::Digest;
 use serde::Deserialize;
 use sha1::Sha1;
@@ -87,9 +86,7 @@ impl UpyunCore {
 
     pub fn sign(&self, req: &mut Request<Buffer>) -> Result<()> {
         // get rfc1123 date
-        let date = Timestamp::now()
-            .strftime("%a, %d %b %Y %H:%M:%S GMT")
-            .to_string();
+        let date = Timestamp::now().strftime("%a, %d %b %Y %H:%M:%S GMT");
         let authorization =
             self.signer
                 .authorization(&date, req.method().as_str(), req.uri().path());
diff --git a/core/src/services/upyun/lister.rs 
b/core/src/services/upyun/lister.rs
index d86249bc4..a9367def1 100644
--- a/core/src/services/upyun/lister.rs
+++ b/core/src/services/upyun/lister.rs
@@ -89,7 +89,7 @@ impl oio::PageList for UpyunLister {
                 let m = Metadata::new(EntryMode::FILE)
                     .with_content_length(file.length)
                     .with_content_type(file.type_field)
-                    
.with_last_modified(parse_datetime_from_timestamp(file.last_modified)?);
+                    
.with_last_modified(Timestamp::from_second(file.last_modified)?);
                 Entry::new(&path, m)
             };
 
diff --git a/core/src/services/vercel_blob/core.rs 
b/core/src/services/vercel_blob/core.rs
index 6769b6189..597969657 100644
--- a/core/src/services/vercel_blob/core.rs
+++ b/core/src/services/vercel_blob/core.rs
@@ -395,7 +395,7 @@ pub fn parse_blob(blob: &Blob) -> Result<Metadata> {
         md.set_content_type(&content_type);
     }
     md.set_content_length(blob.size);
-    md.set_last_modified(parse_datetime_from_rfc3339(&blob.uploaded_at)?);
+    md.set_last_modified(blob.uploaded_at.parse::<Timestamp>()?);
     md.set_content_disposition(&blob.content_disposition);
     Ok(md)
 }
diff --git a/core/src/services/webdav/core.rs b/core/src/services/webdav/core.rs
index 515f8cece..065aaa716 100644
--- a/core/src/services/webdav/core.rs
+++ b/core/src/services/webdav/core.rs
@@ -428,7 +428,7 @@ pub fn parse_propstat(propstat: &Propstat) -> 
Result<Metadata> {
     }
 
     // https://www.rfc-editor.org/rfc/rfc4918#section-14.18
-    m.set_last_modified(parse_datetime_from_rfc2822(getlastmodified)?);
+    m.set_last_modified(Timestamp::parse_rfc2822(getlastmodified)?);
 
     // the storage services have returned all the properties
     Ok(m)
diff --git a/core/src/services/webhdfs/backend.rs 
b/core/src/services/webhdfs/backend.rs
index 3ec8cba29..30e468824 100644
--- a/core/src/services/webhdfs/backend.rs
+++ b/core/src/services/webhdfs/backend.rs
@@ -310,7 +310,7 @@ impl Access for WebhdfsBackend {
                     FileStatusType::Directory => Metadata::new(EntryMode::DIR),
                     FileStatusType::File => Metadata::new(EntryMode::FILE)
                         .with_content_length(file_status.length)
-                        
.with_last_modified(parse_datetime_from_timestamp_millis(
+                        .with_last_modified(Timestamp::from_millisecond(
                             file_status.modification_time,
                         )?),
                 };
diff --git a/core/src/services/webhdfs/lister.rs 
b/core/src/services/webhdfs/lister.rs
index dae855e79..4fa0e2e71 100644
--- a/core/src/services/webhdfs/lister.rs
+++ b/core/src/services/webhdfs/lister.rs
@@ -110,9 +110,7 @@ impl oio::PageList for WebhdfsLister {
                 FileStatusType::Directory => Metadata::new(EntryMode::DIR),
                 FileStatusType::File => Metadata::new(EntryMode::FILE)
                     .with_content_length(status.length)
-                    .with_last_modified(parse_datetime_from_timestamp_millis(
-                        status.modification_time,
-                    )?),
+                    
.with_last_modified(Timestamp::from_millisecond(status.modification_time)?),
             };
 
             if meta.mode().is_file() {
diff --git a/core/src/services/yandex_disk/core.rs 
b/core/src/services/yandex_disk/core.rs
index 70bad5556..33283dbde 100644
--- a/core/src/services/yandex_disk/core.rs
+++ b/core/src/services/yandex_disk/core.rs
@@ -298,7 +298,7 @@ pub(super) fn parse_info(mf: MetainformationResponse) -> 
Result<Metadata> {
 
     let mut m = Metadata::new(mode);
 
-    m.set_last_modified(parse_datetime_from_rfc3339(&mf.modified)?);
+    m.set_last_modified(mf.modified.parse::<Timestamp>()?);
 
     if let Some(md5) = mf.md5 {
         m.set_content_md5(&md5);
diff --git a/core/src/types/metadata.rs b/core/src/types/metadata.rs
index d09a481fe..901979dc4 100644
--- a/core/src/types/metadata.rs
+++ b/core/src/types/metadata.rs
@@ -17,7 +17,6 @@
 
 use crate::raw::*;
 use crate::*;
-use jiff::Timestamp;
 use std::collections::HashMap;
 
 /// Metadata contains all the information related to a specific path.
diff --git a/core/src/types/operator/operator_futures.rs 
b/core/src/types/operator/operator_futures.rs
index f761316b2..eeb594972 100644
--- a/core/src/types/operator/operator_futures.rs
+++ b/core/src/types/operator/operator_futures.rs
@@ -27,7 +27,6 @@ use std::time::Duration;
 use crate::raw::*;
 use crate::*;
 use futures::Future;
-use jiff::Timestamp;
 
 /// OperatorFuture is the future generated by [`Operator`].
 ///
@@ -390,8 +389,8 @@ impl<F: Future<Output = Result<Buffer>>> FutureRead<F> {
     /// # Ok(())
     /// # }
     /// ```
-    pub fn if_modified_since(mut self, v: Timestamp) -> Self {
-        self.args.if_modified_since = Some(v);
+    pub fn if_modified_since(mut self, v: impl Into<Timestamp>) -> Self {
+        self.args.if_modified_since = Some(v.into());
         self
     }
 
@@ -414,8 +413,8 @@ impl<F: Future<Output = Result<Buffer>>> FutureRead<F> {
     /// # Ok(())
     /// # }
     /// ```
-    pub fn if_unmodified_since(mut self, v: Timestamp) -> Self {
-        self.args.if_unmodified_since = Some(v);
+    pub fn if_unmodified_since(mut self, v: impl Into<Timestamp>) -> Self {
+        self.args.if_unmodified_since = Some(v.into());
         self
     }
 }
@@ -585,8 +584,8 @@ impl<F: Future<Output = Result<Reader>>> FutureReader<F> {
     /// # Ok(())
     /// # }
     /// ```
-    pub fn if_modified_since(mut self, v: Timestamp) -> Self {
-        self.args.if_modified_since = Some(v);
+    pub fn if_modified_since(mut self, v: impl Into<Timestamp>) -> Self {
+        self.args.if_modified_since = Some(v.into());
         self
     }
 
@@ -609,8 +608,8 @@ impl<F: Future<Output = Result<Reader>>> FutureReader<F> {
     /// # Ok(())
     /// # }
     /// ```
-    pub fn if_unmodified_since(mut self, v: Timestamp) -> Self {
-        self.args.if_unmodified_since = Some(v);
+    pub fn if_unmodified_since(mut self, v: impl Into<Timestamp>) -> Self {
+        self.args.if_unmodified_since = Some(v.into());
         self
     }
 }
diff --git a/core/src/types/options.rs b/core/src/types/options.rs
index e754e6d40..d6d81a5a8 100644
--- a/core/src/types/options.rs
+++ b/core/src/types/options.rs
@@ -17,8 +17,7 @@
 
 //! Options module provides options definitions for operations.
 
-use crate::raw::BytesRange;
-use jiff::Timestamp;
+use crate::raw::{BytesRange, Timestamp};
 use std::collections::HashMap;
 
 /// Options for delete operations.
diff --git a/integrations/cloud_filter/src/lib.rs 
b/integrations/cloud_filter/src/lib.rs
index 6e635f0cb..0a769ff7e 100644
--- a/integrations/cloud_filter/src/lib.rs
+++ b/integrations/cloud_filter/src/lib.rs
@@ -231,7 +231,11 @@ impl Filter for CloudFilter {
                             .size(metadata.content_length())
                             .written(
                                 FileTime::from_unix_time(
-                                    
metadata.last_modified().unwrap_or_default().as_second(),
+                                    metadata
+                                        .last_modified()
+                                        .unwrap_or_default()
+                                        .into_inner()
+                                        .as_second(),
                                 )
                                 .expect("valid time"),
                             )
diff --git a/integrations/dav-server/src/metadata.rs 
b/integrations/dav-server/src/metadata.rs
index 16099efd3..1286e9cb8 100644
--- a/integrations/dav-server/src/metadata.rs
+++ b/integrations/dav-server/src/metadata.rs
@@ -40,7 +40,7 @@ impl DavMetaData for OpendalMetaData {
 
     fn modified(&self) -> FsResult<SystemTime> {
         match self.metadata.last_modified() {
-            Some(t) => Ok(t.into()),
+            Some(t) => Ok(t.as_system_time()),
             None => Err(FsError::GeneralFailure),
         }
     }
@@ -60,6 +60,6 @@ impl DavMetaData for OpendalMetaData {
     fn status_changed(&self) -> FsResult<SystemTime> {
         self.metadata
             .last_modified()
-            .map_or(Err(FsError::GeneralFailure), |t| Ok(t.into()))
+            .map_or(Err(FsError::GeneralFailure), |t| Ok(t.as_system_time()))
     }
 }
diff --git a/integrations/fuse3/src/file_system.rs 
b/integrations/fuse3/src/file_system.rs
index e0a20c7a6..7876fa9b6 100644
--- a/integrations/fuse3/src/file_system.rs
+++ b/integrations/fuse3/src/file_system.rs
@@ -776,7 +776,10 @@ const fn entry_mode2file_type(mode: EntryMode) -> FileType 
{
 }
 
 fn metadata2file_attr(metadata: &Metadata, atime: SystemTime, uid: u32, gid: 
u32) -> FileAttr {
-    let last_modified = metadata.last_modified().map(|t| 
t.into()).unwrap_or(atime);
+    let last_modified = metadata
+        .last_modified()
+        .map(|t| t.into_inner().into())
+        .unwrap_or(atime);
     let kind = entry_mode2file_type(metadata.mode());
     FileAttr {
         size: metadata.content_length(),
diff --git a/integrations/object_store/Cargo.toml 
b/integrations/object_store/Cargo.toml
index d1f91f6c5..355aafb72 100644
--- a/integrations/object_store/Cargo.toml
+++ b/integrations/object_store/Cargo.toml
@@ -41,7 +41,6 @@ async-trait = "0.1"
 bytes = "1"
 chrono = { version = "0.4.42", features = ["std", "clock"] }
 futures = "0.3"
-jiff = { version = "0.2.15 "}
 object_store = "0.12.3"
 opendal = { version = "0.54.0", path = "../../core", default-features = false }
 pin-project = "1.1"
diff --git a/integrations/object_store/src/lib.rs 
b/integrations/object_store/src/lib.rs
index 983612882..7a0cf07ee 100644
--- a/integrations/object_store/src/lib.rs
+++ b/integrations/object_store/src/lib.rs
@@ -98,10 +98,14 @@ mod assert_send {
     }
 }
 
-fn timestamp_to_datetime(ts: jiff::Timestamp) -> 
Option<chrono::DateTime<chrono::Utc>> {
-    chrono::DateTime::<chrono::Utc>::from_timestamp(ts.as_second(), 
ts.subsec_nanosecond() as u32)
+fn timestamp_to_datetime(ts: opendal::raw::Timestamp) -> 
Option<chrono::DateTime<chrono::Utc>> {
+    let jiff_ts = ts.into_inner();
+    chrono::DateTime::<chrono::Utc>::from_timestamp(
+        jiff_ts.as_second(),
+        jiff_ts.subsec_nanosecond() as u32,
+    )
 }
 
-fn datetime_to_timestamp(dt: chrono::DateTime<chrono::Utc>) -> 
Option<jiff::Timestamp> {
-    jiff::Timestamp::new(dt.timestamp(), dt.timestamp_subsec_nanos() as 
i32).ok()
+fn datetime_to_timestamp(dt: chrono::DateTime<chrono::Utc>) -> 
Option<opendal::raw::Timestamp> {
+    opendal::raw::Timestamp::new(dt.timestamp(), dt.timestamp_subsec_nanos() 
as i32).ok()
 }
diff --git a/integrations/unftp-sbe/src/lib.rs 
b/integrations/unftp-sbe/src/lib.rs
index d48733523..31c3994c2 100644
--- a/integrations/unftp-sbe/src/lib.rs
+++ b/integrations/unftp-sbe/src/lib.rs
@@ -101,9 +101,12 @@ impl storage::Metadata for OpendalMetadata {
     }
 
     fn modified(&self) -> storage::Result<std::time::SystemTime> {
-        self.0.last_modified().map(Into::into).ok_or_else(|| {
-            storage::Error::new(storage::ErrorKind::LocalError, "no last 
modified time")
-        })
+        self.0
+            .last_modified()
+            .map(|t| t.into_inner().into())
+            .ok_or_else(|| {
+                storage::Error::new(storage::ErrorKind::LocalError, "no last 
modified time")
+            })
     }
 
     fn gid(&self) -> u32 {

Reply via email to