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 {