This is an automated email from the ASF dual-hosted git repository.
tison 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 6c8eddbf5 refactor!: migrate chrono to jiff (#6643)
6c8eddbf5 is described below
commit 6c8eddbf5b0649c3e4b955e560f2003af4b95903
Author: tison <[email protected]>
AuthorDate: Fri Oct 10 18:15:40 2025 +0800
refactor!: migrate chrono to jiff (#6643)
Signed-off-by: tison <[email protected]>
---
bin/oay/Cargo.lock | 321 ++++++++++++++++++--------
bin/oay/Cargo.toml | 8 +-
bin/oay/src/bin/oay.rs | 2 +-
bin/oay/src/bin/webdav.rs | 2 +-
bin/oay/src/services/s3/service.rs | 6 +-
bin/oli/Cargo.lock | 54 ++++-
bin/oli/tests/integration/test_utils.rs | 4 +
bindings/c/src/metadata.rs | 2 +-
bindings/cpp/Cargo.toml | 10 +-
bindings/cpp/src/types.rs | 5 +-
bindings/dart/rust/src/api/opendal_api.rs | 2 +-
bindings/haskell/Cargo.toml | 2 +-
bindings/haskell/src/types.rs | 3 +-
bindings/java/Cargo.toml | 6 +-
bindings/java/src/convert.rs | 23 +-
bindings/java/src/lib.rs | 8 +-
bindings/nodejs/src/lib.rs | 2 +-
bindings/ocaml/src/operator/metadata.rs | 2 +-
bindings/python/Cargo.toml | 4 +-
bindings/python/src/metadata.rs | 8 +-
bindings/python/src/options.rs | 11 +-
core/Cargo.lock | 12 +-
core/Cargo.toml | 5 +-
core/src/lib.rs | 4 +-
core/src/raw/adapters/typed_kv/api.rs | 14 +-
core/src/raw/http_util/header.rs | 5 +-
core/src/raw/{chrono_util.rs => jiff_util.rs} | 82 ++++---
core/src/raw/mod.rs | 4 +-
core/src/raw/ops.rs | 33 ++-
core/src/raw/std_io_util.rs | 2 +-
core/src/services/aliyun_drive/backend.rs | 18 +-
core/src/services/aliyun_drive/core.rs | 6 +-
core/src/services/aliyun_drive/lister.rs | 21 +-
core/src/services/alluxio/core.rs | 2 +-
core/src/services/b2/core.rs | 14 +-
core/src/services/cacache/backend.rs | 14 +-
core/src/services/cloudflare_kv/backend.rs | 16 +-
core/src/services/cloudflare_kv/writer.rs | 6 +-
core/src/services/compfs/backend.rs | 4 +-
core/src/services/dashmap/writer.rs | 4 +-
core/src/services/dbfs/backend.rs | 2 +-
core/src/services/dbfs/lister.rs | 4 +-
core/src/services/dropbox/builder.rs | 6 +-
core/src/services/dropbox/core.rs | 27 +--
core/src/services/fs/core.rs | 12 +-
core/src/services/fs/writer.rs | 8 +-
core/src/services/ftp/backend.rs | 2 +-
core/src/services/ftp/lister.rs | 2 +-
core/src/services/gdrive/backend.rs | 11 +-
core/src/services/gdrive/builder.rs | 8 +-
core/src/services/gdrive/core.rs | 25 +-
core/src/services/github/core.rs | 5 +-
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/koofr/backend.rs | 2 +-
core/src/services/koofr/lister.rs | 2 +-
core/src/services/lakefs/backend.rs | 5 +-
core/src/services/lakefs/lister.rs | 8 +-
core/src/services/mini_moka/writer.rs | 6 +-
core/src/services/monoiofs/backend.rs | 12 +-
core/src/services/monoiofs/writer.rs | 10 +-
core/src/services/onedrive/builder.rs | 12 +-
core/src/services/onedrive/core.rs | 18 +-
core/src/services/onedrive/graph_model.rs | 2 +-
core/src/services/seafile/lister.rs | 2 +-
core/src/services/sftp/utils.rs | 5 +-
core/src/services/upyun/core.rs | 5 +-
core/src/services/upyun/lister.rs | 2 +-
core/src/services/webhdfs/backend.rs | 2 +-
core/src/services/webhdfs/lister.rs | 2 +-
core/src/types/metadata.rs | 14 +-
core/src/types/operator/operator_futures.rs | 38 ++-
core/src/types/options.rs | 19 +-
core/tests/behavior/async_read.rs | 16 +-
integrations/cloud_filter/src/lib.rs | 2 +-
integrations/object_store/Cargo.toml | 2 +
integrations/object_store/src/lib.rs | 8 +
integrations/object_store/src/service/core.rs | 16 +-
integrations/object_store/src/store.rs | 22 +-
integrations/object_store/src/utils.rs | 6 +-
82 files changed, 637 insertions(+), 474 deletions(-)
diff --git a/bin/oay/Cargo.lock b/bin/oay/Cargo.lock
index 69607408b..ec05882b4 100644
--- a/bin/oay/Cargo.lock
+++ b/bin/oay/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"
@@ -32,15 +32,6 @@ version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
-[[package]]
-name = "android_system_properties"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
-dependencies = [
- "libc",
-]
-
[[package]]
name = "anyhow"
version = "1.0.100"
@@ -192,24 +183,14 @@ source =
"registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
-name = "chrono"
-version = "0.4.42"
+name = "colored"
+version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
+checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
dependencies = [
- "iana-time-zone",
- "js-sys",
- "num-traits",
- "wasm-bindgen",
- "windows-link 0.2.1",
+ "windows-sys 0.52.0",
]
-[[package]]
-name = "core-foundation-sys"
-version = "0.8.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
-
[[package]]
name = "cpufeatures"
version = "0.2.17"
@@ -322,22 +303,23 @@ version = "1.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005"
-[[package]]
-name = "env_filter"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
-dependencies = [
- "log",
- "regex",
-]
-
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+[[package]]
+name = "erased-serde"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "259d404d09818dec19332e31d94558aeb442fea04c817006456c24b5460bbd4b"
+dependencies = [
+ "serde",
+ "serde_core",
+ "typeid",
+]
+
[[package]]
name = "errno"
version = "0.3.12"
@@ -667,30 +649,6 @@ dependencies = [
"tracing",
]
-[[package]]
-name = "iana-time-zone"
-version = "0.1.63"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
-dependencies = [
- "android_system_properties",
- "core-foundation-sys",
- "iana-time-zone-haiku",
- "js-sys",
- "log",
- "wasm-bindgen",
- "windows-core",
-]
-
-[[package]]
-name = "iana-time-zone-haiku"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
-dependencies = [
- "cc",
-]
-
[[package]]
name = "icu_collections"
version = "2.0.0"
@@ -843,9 +801,9 @@ checksum =
"4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jiff"
-version = "0.2.14"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
+checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
dependencies = [
"jiff-static",
"jiff-tzdb-platform",
@@ -858,9 +816,9 @@ dependencies = [
[[package]]
name = "jiff-static"
-version = "0.2.14"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
+checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
dependencies = [
"proc-macro2",
"quote",
@@ -931,17 +889,76 @@ name = "log"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+dependencies = [
+ "sval",
+ "sval_ref",
+ "value-bag",
+]
[[package]]
name = "logforth"
-version = "0.27.0"
+version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bb3bacbca013b1a4d9f342501b6aa28eb32a6aa33bc804792fad83d661a59d5"
+checksum = "bd048889d633cac5c189eca703f5c5ed65210d358eb5910a478e233d42528d6e"
+dependencies = [
+ "logforth-append-file",
+ "logforth-bridge-log",
+ "logforth-core",
+ "logforth-layout-json",
+ "logforth-layout-text",
+]
+
+[[package]]
+name = "logforth-append-file"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aeb66a16ac0f5cdd6a0e7005c6e1fa2744e915244941ac6cd01bd56de2995f48"
dependencies = [
- "anyhow",
- "env_filter",
"jiff",
+ "logforth-core",
+]
+
+[[package]]
+name = "logforth-bridge-log"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "392ff9723d68a943ccffabe03b5272f7c93104f0008a6c7357ef888c21ab6297"
+dependencies = [
"log",
+ "logforth-core",
+]
+
+[[package]]
+name = "logforth-core"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7666819ed32e38aabb45959a632b0f9c25fc77e60c824b02a5fcd87ab626f6ed"
+dependencies = [
+ "anyhow",
+ "value-bag",
+]
+
+[[package]]
+name = "logforth-layout-json"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49e1db5d0f5b1bc57134ff9d1ed3889910d230545f3d249bde44bac0e8a8724f"
+dependencies = [
+ "jiff",
+ "logforth-core",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "logforth-layout-text"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c00c67d92539b26edbba5e43ce8f5b97d62412c1cfc9463400f50cfad2f1f1bf"
+dependencies = [
+ "colored",
+ "jiff",
+ "logforth-core",
]
[[package]]
@@ -1023,25 +1040,16 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
-[[package]]
-name = "num-traits"
-version = "0.2.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
-dependencies = [
- "autocfg",
-]
-
[[package]]
name = "oay"
version = "0.41.23"
dependencies = [
"anyhow",
"axum",
- "chrono",
"dav-server",
"dav-server-opendalfs",
"futures-util",
+ "jiff",
"log",
"logforth",
"opendal",
@@ -1075,11 +1083,11 @@ dependencies = [
"backon",
"base64 0.22.1",
"bytes",
- "chrono",
"futures",
"getrandom 0.2.16",
"http",
"http-body",
+ "jiff",
"log",
"md-5",
"percent-encoding",
@@ -1502,6 +1510,15 @@ dependencies = [
"serde_derive",
]
+[[package]]
+name = "serde_buf"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a86be9d6c7d34718d2ec6f56c8d6a4671d1a7357c2a6921f47fe5a3ee6056cc"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "serde_core"
version = "1.0.228"
@@ -1522,6 +1539,15 @@ dependencies = [
"syn 2.0.101",
]
+[[package]]
+name = "serde_fmt"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1d4ddca14104cd60529e8c7f7ba71a2c8acd8f7f5cfcdc2faf97eeb7c3010a4"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "serde_json"
version = "1.0.140"
@@ -1629,6 +1655,84 @@ version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+[[package]]
+name = "sval"
+version = "2.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d94c4464e595f0284970fd9c7e9013804d035d4a61ab74b113242c874c05814d"
+
+[[package]]
+name = "sval_buffer"
+version = "2.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0f46e34b20a39e6a2bf02b926983149b3af6609fd1ee8a6e63f6f340f3e2164"
+dependencies = [
+ "sval",
+ "sval_ref",
+]
+
+[[package]]
+name = "sval_dynamic"
+version = "2.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03d0970e53c92ab5381d3b2db1828da8af945954d4234225f6dd9c3afbcef3f5"
+dependencies = [
+ "sval",
+]
+
+[[package]]
+name = "sval_fmt"
+version = "2.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43e5e6e1613e1e7fc2e1a9fdd709622e54c122ceb067a60d170d75efd491a839"
+dependencies = [
+ "itoa",
+ "ryu",
+ "sval",
+]
+
+[[package]]
+name = "sval_json"
+version = "2.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aec382f7bfa6e367b23c9611f129b94eb7daaf3d8fae45a8d0a0211eb4d4c8e6"
+dependencies = [
+ "itoa",
+ "ryu",
+ "sval",
+]
+
+[[package]]
+name = "sval_nested"
+version = "2.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3049d0f99ce6297f8f7d9953b35a0103b7584d8f638de40e64edb7105fa578ae"
+dependencies = [
+ "sval",
+ "sval_buffer",
+ "sval_ref",
+]
+
+[[package]]
+name = "sval_ref"
+version = "2.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f88913e77506085c0a8bf6912bb6558591a960faf5317df6c1d9b227224ca6e1"
+dependencies = [
+ "sval",
+]
+
+[[package]]
+name = "sval_serde"
+version = "2.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f579fd7254f4be6cd7b450034f856b78523404655848789c451bacc6aa8b387d"
+dependencies = [
+ "serde_core",
+ "sval",
+ "sval_nested",
+]
+
[[package]]
name = "syn"
version = "1.0.109"
@@ -1910,6 +2014,12 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+[[package]]
+name = "typeid"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
+
[[package]]
name = "typenum"
version = "1.18.0"
@@ -1963,6 +2073,43 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "value-bag"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "943ce29a8a743eb10d6082545d861b24f9d1b160b7d741e0f2cdf726bec909c5"
+dependencies = [
+ "value-bag-serde1",
+ "value-bag-sval2",
+]
+
+[[package]]
+name = "value-bag-serde1"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35540706617d373b118d550d41f5dfe0b78a0c195dc13c6815e92e2638432306"
+dependencies = [
+ "erased-serde",
+ "serde",
+ "serde_buf",
+ "serde_fmt",
+]
+
+[[package]]
+name = "value-bag-sval2"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fe7e140a2658cc16f7ee7a86e413e803fc8f9b5127adc8755c19f9fefa63a52"
+dependencies = [
+ "sval",
+ "sval_buffer",
+ "sval_dynamic",
+ "sval_fmt",
+ "sval_json",
+ "sval_ref",
+ "sval_serde",
+]
+
[[package]]
name = "version_check"
version = "0.9.5"
@@ -2124,7 +2271,7 @@ dependencies = [
"windows-collections",
"windows-core",
"windows-future",
- "windows-link 0.1.1",
+ "windows-link",
"windows-numerics",
]
@@ -2145,7 +2292,7 @@ checksum =
"c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [
"windows-implement",
"windows-interface",
- "windows-link 0.1.1",
+ "windows-link",
"windows-result",
"windows-strings",
]
@@ -2157,7 +2304,7 @@ source =
"registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
dependencies = [
"windows-core",
- "windows-link 0.1.1",
+ "windows-link",
"windows-threading",
]
@@ -2189,12 +2336,6 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
-[[package]]
-name = "windows-link"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
-
[[package]]
name = "windows-numerics"
version = "0.2.0"
@@ -2202,7 +2343,7 @@ source =
"registry+https://github.com/rust-lang/crates.io-index"
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
"windows-core",
- "windows-link 0.1.1",
+ "windows-link",
]
[[package]]
@@ -2211,7 +2352,7 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
- "windows-link 0.1.1",
+ "windows-link",
]
[[package]]
@@ -2220,7 +2361,7 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
- "windows-link 0.1.1",
+ "windows-link",
]
[[package]]
@@ -2263,7 +2404,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
dependencies = [
- "windows-link 0.1.1",
+ "windows-link",
]
[[package]]
diff --git a/bin/oay/Cargo.toml b/bin/oay/Cargo.toml
index f664e32ab..b0cf4fdfc 100644
--- a/bin/oay/Cargo.toml
+++ b/bin/oay/Cargo.toml
@@ -40,14 +40,14 @@ frontends-webdav = [
]
[dependencies]
-anyhow = "1"
-axum = "0.8"
-chrono = "0.4.31"
+anyhow = { version = "1.0.100" }
+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.27.0", default-features = false }
+logforth = { version = "0.28.1", features = ["starter-log"] }
opendal = { version = "0.54.0", path = "../../core", features = [
"services-fs",
] }
diff --git a/bin/oay/src/bin/oay.rs b/bin/oay/src/bin/oay.rs
index 703b434f9..ff2f6d3d0 100644
--- a/bin/oay/src/bin/oay.rs
+++ b/bin/oay/src/bin/oay.rs
@@ -34,7 +34,7 @@ async fn main() -> Result<()> {
}
async fn s3() -> Result<()> {
- logforth::stderr().apply();
+ logforth::starter_log::stderr().apply();
let cfg: Config =
toml::from_str(&std::fs::read_to_string("oay.toml").context("failed to
open oay.toml")?)?;
diff --git a/bin/oay/src/bin/webdav.rs b/bin/oay/src/bin/webdav.rs
index b2975b541..8ba6c1675 100644
--- a/bin/oay/src/bin/webdav.rs
+++ b/bin/oay/src/bin/webdav.rs
@@ -25,7 +25,7 @@ use opendal::services::Fs;
#[tokio::main]
async fn main() -> Result<()> {
- logforth::stderr().apply();
+ logforth::starter_log::stderr().apply();
let cfg: Config = Config {
backend: oay::BackendConfig {
diff --git a/bin/oay/src/services/s3/service.rs
b/bin/oay/src/services/s3/service.rs
index 01a0d84c3..af314aa37 100644
--- a/bin/oay/src/services/s3/service.rs
+++ b/bin/oay/src/services/s3/service.rs
@@ -24,7 +24,6 @@ use axum::http::StatusCode;
use axum::response::IntoResponse;
use axum::response::Response;
use axum::routing::get;
-use chrono::SecondsFormat;
use futures_util::StreamExt;
use opendal::Operator;
use serde::Deserialize;
@@ -117,10 +116,7 @@ async fn handle_list_objects(
} else {
contents.push(Object {
key: v.path().to_string(),
- last_modified: meta
- .last_modified()
- .unwrap_or_default()
- .to_rfc3339_opts(SecondsFormat::Millis, true),
+ last_modified: format!("{:.6}",
meta.last_modified().unwrap_or_default()),
etag: meta.etag().unwrap_or_default().to_string(),
size: meta.content_length(),
});
diff --git a/bin/oli/Cargo.lock b/bin/oli/Cargo.lock
index 5841135f0..a5af6a1fe 100644
--- a/bin/oli/Cargo.lock
+++ b/bin/oli/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"
@@ -1139,6 +1139,47 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+[[package]]
+name = "jiff"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
+dependencies = [
+ "jiff-static",
+ "jiff-tzdb-platform",
+ "log",
+ "portable-atomic",
+ "portable-atomic-util",
+ "serde",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "jiff-static"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "jiff-tzdb"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1283705eb0a21404d2bfd6eef2a7593d240bc42a0bdb39db0ad6fa2ec026524"
+
+[[package]]
+name = "jiff-tzdb-platform"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8"
+dependencies = [
+ "jiff-tzdb",
+]
+
[[package]]
name = "js-sys"
version = "0.3.77"
@@ -1386,13 +1427,13 @@ dependencies = [
"backon",
"base64",
"bytes",
- "chrono",
"crc32c",
"futures",
"getrandom 0.2.16",
"ghac",
"http",
"http-body",
+ "jiff",
"log",
"md-5",
"percent-encoding",
@@ -1549,6 +1590,15 @@ version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
+dependencies = [
+ "portable-atomic",
+]
+
[[package]]
name = "potential_utf"
version = "0.1.2"
diff --git a/bin/oli/tests/integration/test_utils.rs
b/bin/oli/tests/integration/test_utils.rs
index 69701f7bd..78e0c45aa 100644
--- a/bin/oli/tests/integration/test_utils.rs
+++ b/bin/oli/tests/integration/test_utils.rs
@@ -143,6 +143,10 @@ pub const REPLACEMENTS: &[(&str, &str)] = &[
r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{9} UTC)",
"[TIMESTAMP]",
),
+ (
+ r"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{9}Z)",
+ "[TIMESTAMP]",
+ ),
];
pub static REPLACEMENT_REGEXS: std::sync::LazyLock<Vec<(regex::Regex,
String)>> =
std::sync::LazyLock::new(|| {
diff --git a/bindings/c/src/metadata.rs b/bindings/c/src/metadata.rs
index df381f367..a47407053 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.timestamp_millis(),
+ Some(time) => time.as_millisecond(),
}
}
}
diff --git a/bindings/cpp/Cargo.toml b/bindings/cpp/Cargo.toml
index 50af3560e..e9e5cf69f 100644
--- a/bindings/cpp/Cargo.toml
+++ b/bindings/cpp/Cargo.toml
@@ -30,17 +30,17 @@ rust-version = "1.85"
crate-type = ["staticlib"]
[dependencies]
-anyhow = "1.0"
-chrono = "0.4"
-cxx = "1.0"
+anyhow = { version = "1.0.100" }
+cxx = { version = "1.0.186" }
cxx-async = { version = "0.1.3", optional = true }
-futures = "0.3"
+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"] }
[build-dependencies]
-cxx-build = "1.0"
+cxx-build = { version = "1.0.186" }
[features]
async = ["cxx-async", "cxx/c++20"]
diff --git a/bindings/cpp/src/types.rs b/bindings/cpp/src/types.rs
index 8182b5aab..2e522bfde 100644
--- a/bindings/cpp/src/types.rs
+++ b/bindings/cpp/src/types.rs
@@ -29,10 +29,7 @@ impl From<od::Metadata> for ffi::Metadata {
let content_type = meta.content_type().map(ToOwned::to_owned).into();
let content_encoding =
meta.content_encoding().map(ToOwned::to_owned).into();
let etag = meta.etag().map(ToOwned::to_owned).into();
- let last_modified = meta
- .last_modified()
- .map(|time| time.to_rfc3339_opts(chrono::SecondsFormat::Nanos,
false))
- .into();
+ let last_modified = meta.last_modified().map(|time|
time.to_string()).into();
let version = meta.version().map(ToOwned::to_owned).into();
let is_current = meta.is_current().into();
let is_deleted = meta.is_deleted();
diff --git a/bindings/dart/rust/src/api/opendal_api.rs
b/bindings/dart/rust/src/api/opendal_api.rs
index d9a7fe636..8030abe0b 100644
--- a/bindings/dart/rust/src/api/opendal_api.rs
+++ b/bindings/dart/rust/src/api/opendal_api.rs
@@ -145,6 +145,6 @@ impl Metadata {
/// We will output this time in RFC3339 format like
`1996-12-19T16:39:57+08:00`.
#[frb(sync, getter)]
pub fn last_modified(&self) -> Option<String> {
- self.0.last_modified().map(|ta| ta.to_rfc3339())
+ self.0.last_modified().map(|ta| ta.to_string())
}
}
diff --git a/bindings/haskell/Cargo.toml b/bindings/haskell/Cargo.toml
index e06dfda9c..8cd44f0f4 100644
--- a/bindings/haskell/Cargo.toml
+++ b/bindings/haskell/Cargo.toml
@@ -31,7 +31,7 @@ crate-type = ["cdylib"]
doc = false
[dependencies]
-chrono = "0.4"
+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/haskell/src/types.rs b/bindings/haskell/src/types.rs
index 1d8598b02..0e17c366b 100644
--- a/bindings/haskell/src/types.rs
+++ b/bindings/haskell/src/types.rs
@@ -19,7 +19,6 @@ use std::ffi::CString;
use std::ffi::c_char;
use ::opendal as od;
-use chrono::SecondsFormat;
#[repr(C)]
#[derive(Debug)]
@@ -119,7 +118,7 @@ impl From<od::Metadata> for Metadata {
};
let last_modified = match val.last_modified() {
- Some(s) => unsafe {
leak_str(s.to_rfc3339_opts(SecondsFormat::Nanos, false).as_str()) },
+ Some(s) => unsafe { leak_str(s.to_string().as_str()) },
None => std::ptr::null(),
};
diff --git a/bindings/java/Cargo.toml b/bindings/java/Cargo.toml
index 6c0df7f6e..0d83468ac 100644
--- a/bindings/java/Cargo.toml
+++ b/bindings/java/Cargo.toml
@@ -150,14 +150,14 @@ services-yandex-disk = ["opendal/services-yandex-disk"]
services-compfs = ["opendal/services-compfs"]
[dependencies]
-anyhow = "1.0.71"
-jni = "0.21.1"
+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 = [
"blocking",
] }
tokio = { version = "1.28.1", features = ["full"] }
-chrono = "0.4"
# This is not optimal. See also the Cargo issue:
# https://github.com/rust-lang/cargo/issues/1197#issuecomment-1641086954
diff --git a/bindings/java/src/convert.rs b/bindings/java/src/convert.rs
index 841cb1a44..bd0706e4a 100644
--- a/bindings/java/src/convert.rs
+++ b/bindings/java/src/convert.rs
@@ -16,7 +16,7 @@
// under the License.
use crate::Result;
-use chrono::{DateTime, Utc};
+use jiff::Timestamp;
use jni::JNIEnv;
use jni::objects::JObject;
use jni::objects::JString;
@@ -123,11 +123,11 @@ pub(crate) fn read_jlong_field_to_usize(
}
}
-pub(crate) fn read_instant_field_to_date_time(
+pub(crate) fn read_instant_field_to_timestamp(
env: &mut JNIEnv<'_>,
obj: &JObject,
field: &str,
-) -> Result<Option<DateTime<Utc>>> {
+) -> Result<Option<Timestamp>> {
let result = env.get_field(obj, field, "Ljava/time/Instant;")?.l()?;
if result.is_null() {
return Ok(None);
@@ -137,15 +137,14 @@ pub(crate) fn read_instant_field_to_date_time(
.call_method(&result, "getEpochSecond", "()J", &[])?
.j()?;
let nano = env.call_method(&result, "getNano", "()I", &[])?.i()?;
- DateTime::from_timestamp(epoch_second, nano as u32)
- .map(Some)
- .ok_or_else(|| {
- Error::new(
- ErrorKind::Unexpected,
- format!("Invalid timestamp: seconds={epoch_second},
nanos={nano}"),
- )
- .into()
- })
+ 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()
+ })
}
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 d4edac645..027fb5b8b 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.timestamp()),
- JValue::Long(v.timestamp_subsec_nanos() as jlong),
+ JValue::Long(v.as_second()),
+ JValue::Long(v.subsec_nanosecond() as jlong),
],
)?
.l()?)
@@ -254,12 +254,12 @@ fn make_stat_options(env: &mut JNIEnv, options: &JObject)
-> Result<opendal::opt
Ok(opendal::options::StatOptions {
if_match: convert::read_string_field(env, options, "ifMatch")?,
if_none_match: convert::read_string_field(env, options,
"ifNoneMatch")?,
- if_modified_since: convert::read_instant_field_to_date_time(
+ if_modified_since: convert::read_instant_field_to_timestamp(
env,
options,
"ifModifiedSince",
)?,
- if_unmodified_since: convert::read_instant_field_to_date_time(
+ if_unmodified_since: convert::read_instant_field_to_timestamp(
env,
options,
"ifUnmodifiedSince",
diff --git a/bindings/nodejs/src/lib.rs b/bindings/nodejs/src/lib.rs
index 8faf1026e..736bc1e9e 100644
--- a/bindings/nodejs/src/lib.rs
+++ b/bindings/nodejs/src/lib.rs
@@ -822,7 +822,7 @@ impl Metadata {
/// We will output this time in RFC3339 format like
`1996-12-19T16:39:57+08:00`.
#[napi(getter)]
pub fn last_modified(&self) -> Option<String> {
- self.0.last_modified().map(|ta| ta.to_rfc3339())
+ self.0.last_modified().map(|ta| ta.to_string())
}
/// mode represent this entry's mode.
diff --git a/bindings/ocaml/src/operator/metadata.rs
b/bindings/ocaml/src/operator/metadata.rs
index 551df21af..5dfb9975e 100644
--- a/bindings/ocaml/src/operator/metadata.rs
+++ b/bindings/ocaml/src/operator/metadata.rs
@@ -62,5 +62,5 @@ 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.timestamp())
+ metadata.0.last_modified().map(|t| t.as_second())
}
diff --git a/bindings/python/Cargo.toml b/bindings/python/Cargo.toml
index 0d95e95a7..8aa7ecacd 100644
--- a/bindings/python/Cargo.toml
+++ b/bindings/python/Cargo.toml
@@ -158,15 +158,15 @@ doc = false
[dependencies]
bytes = "1.5.0"
-chrono = "0.4"
dict_derive = "0.6.0"
futures = "0.3.28"
+jiff = { version = "0.2.15" }
# this crate won't be published, we always use the local version
opendal = { version = ">=0", path = "../../core", features = [
"blocking",
"layers-mime-guess"
] }
-pyo3 = { version = "0.26.0", features = ["generate-import-lib", "chrono"] }
+pyo3 = { version = "0.26.0", features = ["generate-import-lib", "jiff-02"] }
pyo3-async-runtimes = { version = "0.26.0", features = ["tokio-runtime"] }
tokio = "1"
diff --git a/bindings/python/src/metadata.rs b/bindings/python/src/metadata.rs
index f7bdd8a14..c15eb77ba 100644
--- a/bindings/python/src/metadata.rs
+++ b/bindings/python/src/metadata.rs
@@ -15,11 +15,9 @@
// specific language governing permissions and limitations
// under the License.
-use chrono::prelude::*;
-use pyo3::prelude::*;
-use std::collections::HashMap;
-
use crate::*;
+use jiff::Timestamp;
+use std::collections::HashMap;
#[pyclass(module = "opendal")]
pub struct Entry(ocore::Entry);
@@ -123,7 +121,7 @@ impl Metadata {
/// Last modified time
#[getter]
- pub fn last_modified(&self) -> Option<DateTime<Utc>> {
+ pub fn last_modified(&self) -> Option<Timestamp> {
self.0.last_modified()
}
diff --git a/bindings/python/src/options.rs b/bindings/python/src/options.rs
index 6e242c735..b40226268 100644
--- a/bindings/python/src/options.rs
+++ b/bindings/python/src/options.rs
@@ -16,12 +16,11 @@
// under the License.
use dict_derive::FromPyObject;
+use jiff::Timestamp;
use opendal::{self as ocore, raw::BytesRange};
use pyo3::pyclass;
use std::collections::HashMap;
-use chrono::{DateTime, Utc};
-
#[pyclass(module = "opendal")]
#[derive(FromPyObject, Default)]
pub struct ReadOptions {
@@ -34,8 +33,8 @@ pub struct ReadOptions {
pub size: Option<usize>,
pub if_match: Option<String>,
pub if_none_match: Option<String>,
- pub if_modified_since: Option<DateTime<Utc>>,
- pub if_unmodified_since: Option<DateTime<Utc>>,
+ pub if_modified_since: Option<Timestamp>,
+ pub if_unmodified_since: Option<Timestamp>,
pub content_type: Option<String>,
pub cache_control: Option<String>,
pub content_disposition: Option<String>,
@@ -147,8 +146,8 @@ pub struct StatOptions {
pub version: Option<String>,
pub if_match: Option<String>,
pub if_none_match: Option<String>,
- pub if_modified_since: Option<DateTime<Utc>>,
- pub if_unmodified_since: Option<DateTime<Utc>>,
+ pub if_modified_since: Option<Timestamp>,
+ pub if_unmodified_since: Option<Timestamp>,
pub content_type: Option<String>,
pub cache_control: Option<String>,
pub content_disposition: Option<String>,
diff --git a/core/Cargo.lock b/core/Cargo.lock
index 6358b81c0..7d1d09700 100644
--- a/core/Cargo.lock
+++ b/core/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 = "Inflector"
@@ -4256,9 +4256,9 @@ dependencies = [
[[package]]
name = "jiff"
-version = "0.2.14"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
+checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49"
dependencies = [
"jiff-static",
"jiff-tzdb-platform",
@@ -4271,9 +4271,9 @@ dependencies = [
[[package]]
name = "jiff-static"
-version = "0.2.14"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
+checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4"
dependencies = [
"proc-macro2",
"quote",
@@ -5313,7 +5313,6 @@ dependencies = [
"bb8",
"bytes",
"cacache",
- "chrono",
"compio",
"crc32c",
"criterion",
@@ -5336,6 +5335,7 @@ dependencies = [
"hmac",
"http 1.3.1",
"http-body 1.0.1",
+ "jiff",
"js-sys",
"libtest-mimic",
"log",
diff --git a/core/Cargo.toml b/core/Cargo.toml
index 26f0c7542..cede6ede5 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -242,16 +242,13 @@ anyhow = { version = "1.0.100", features = ["std"] }
backon = { version = "1.5", features = ["tokio-sleep"] }
base64 = "0.22"
bytes = "1.6"
-chrono = { version = "0.4.42", default-features = false, features = [
- "clock",
- "std",
-] }
futures = { version = "0.3", default-features = false, features = [
"std",
"async-await",
] }
http = "1.1"
http-body = "1"
+jiff = { version = "0.2.15" }
log = "0.4"
md-5 = "0.10"
percent-encoding = "2"
diff --git a/core/src/lib.rs b/core/src/lib.rs
index f7b490f9d..135b373de 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -181,8 +181,8 @@ mod tests {
#[test]
fn assert_size() {
assert_eq!(16, size_of::<Operator>());
- assert_eq!(320, size_of::<Entry>());
- assert_eq!(296, size_of::<Metadata>());
+ assert_eq!(360, size_of::<Entry>());
+ assert_eq!(336, size_of::<Metadata>());
assert_eq!(1, size_of::<EntryMode>());
assert_eq!(24, size_of::<Scheme>());
}
diff --git a/core/src/raw/adapters/typed_kv/api.rs
b/core/src/raw/adapters/typed_kv/api.rs
index ab5498085..a8cd8f884 100644
--- a/core/src/raw/adapters/typed_kv/api.rs
+++ b/core/src/raw/adapters/typed_kv/api.rs
@@ -15,13 +15,6 @@
// specific language governing permissions and limitations
// under the License.
-use std::fmt::Debug;
-use std::future::Future;
-use std::future::ready;
-use std::mem::size_of;
-
-use chrono::Utc;
-
use crate::Buffer;
use crate::EntryMode;
use crate::Error;
@@ -30,6 +23,11 @@ use crate::Metadata;
use crate::Result;
use crate::Scheme;
use crate::raw::MaybeSend;
+use jiff::Timestamp;
+use std::fmt::Debug;
+use std::future::Future;
+use std::future::ready;
+use std::mem::size_of;
/// Adapter is the typed adapter to underlying kv services.
///
@@ -86,7 +84,7 @@ impl Value {
Self {
metadata: Metadata::new(EntryMode::DIR)
.with_content_length(0)
- .with_last_modified(Utc::now()),
+ .with_last_modified(Timestamp::now()),
value: Buffer::new(),
}
}
diff --git a/core/src/raw/http_util/header.rs b/core/src/raw/http_util/header.rs
index f9b26bd4a..09adf864c 100644
--- a/core/src/raw/http_util/header.rs
+++ b/core/src/raw/http_util/header.rs
@@ -19,8 +19,6 @@ use std::collections::HashMap;
use base64::Engine;
use base64::engine::general_purpose;
-use chrono::DateTime;
-use chrono::Utc;
use http::HeaderMap;
use http::HeaderName;
use http::HeaderValue;
@@ -33,6 +31,7 @@ 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;
@@ -94,7 +93,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<DateTime<Utc>>> {
+pub fn parse_last_modified(headers: &HeaderMap) -> Result<Option<Timestamp>> {
parse_header_to_str(headers, LAST_MODIFIED)?
.map(parse_datetime_from_rfc2822)
.transpose()
diff --git a/core/src/raw/chrono_util.rs b/core/src/raw/jiff_util.rs
similarity index 51%
rename from core/src/raw/chrono_util.rs
rename to core/src/raw/jiff_util.rs
index 4d34ee950..9c2b9f75e 100644
--- a/core/src/raw/chrono_util.rs
+++ b/core/src/raw/jiff_util.rs
@@ -15,23 +15,23 @@
// specific language governing permissions and limitations
// under the License.
-use std::time::Duration;
-use std::time::UNIX_EPOCH;
-
-use chrono::DateTime;
-use chrono::Utc;
-
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<DateTime<Utc>> {
- DateTime::parse_from_rfc2822(s)
- .map(|v| v.into())
- .map_err(|e| {
- Error::new(ErrorKind::Unexpected, "parse datetime from rfc2822
failed").set_source(e)
- })
+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.
@@ -41,56 +41,62 @@ pub fn parse_datetime_from_rfc2822(s: &str) ->
Result<DateTime<Utc>> {
/// With a time zone:
///
/// ```
-/// use chrono::Datelike;
+/// 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.date_naive().day(), 28);
+/// assert_eq!(date_time.to_zoned(TimeZone::UTC).day(), 28);
/// # Ok::<(), Error>(())
/// ```
///
/// With the UTC offset of 00:00:
///
/// ```
-/// use chrono::Timelike;
-/// # use opendal::Error;
-/// # use opendal::raw::parse_datetime_from_rfc3339;
+/// 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.hour(), 21);
+/// assert_eq!(date_time.to_zoned(TimeZone::UTC).hour(), 21);
/// # Ok::<(), Error>(())
/// ```
-pub fn parse_datetime_from_rfc3339(s: &str) -> Result<DateTime<Utc>> {
- DateTime::parse_from_rfc3339(s)
- .map(|v| v.into())
- .map_err(|e| {
- Error::new(ErrorKind::Unexpected, "parse datetime from rfc3339
failed").set_source(e)
- })
+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_from_timestamp_millis(s: i64) ->
Result<DateTime<Utc>> {
- let st = UNIX_EPOCH
- .checked_add(Duration::from_millis(s as u64))
- .ok_or_else(|| Error::new(ErrorKind::Unexpected, "input timestamp
overflow"))?;
-
- Ok(st.into())
+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
-pub fn parse_datetime_from_from_timestamp(s: i64) -> Result<DateTime<Utc>> {
- let st = UNIX_EPOCH
- .checked_add(Duration::from_secs(s as u64))
- .ok_or_else(|| Error::new(ErrorKind::Unexpected, "input timestamp
overflow"))?;
+/// 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)
+ })
+}
- Ok(st.into())
+/// 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: DateTime<Utc>) -> String {
- s.format("%a, %d %b %Y %H:%M:%S GMT").to_string()
+pub fn format_datetime_into_http_date(s: Timestamp) -> String {
+ s.strftime("%a, %d %b %Y %H:%M:%S GMT").to_string()
}
#[cfg(test)]
diff --git a/core/src/raw/mod.rs b/core/src/raw/mod.rs
index 9e5c0f896..22879d3a9 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 chrono_util;
-pub use chrono_util::*;
+mod jiff_util;
+pub use jiff_util::*;
#[cfg(feature = "internal-tokio-rt")]
mod tokio_util;
diff --git a/core/src/raw/ops.rs b/core/src/raw/ops.rs
index 416f2fe71..afab131ca 100644
--- a/core/src/raw/ops.rs
+++ b/core/src/raw/ops.rs
@@ -19,14 +19,11 @@
//!
//! By using ops, users can add more context for operation.
-use std::collections::HashMap;
-use std::time::Duration;
-
-use chrono::DateTime;
-use chrono::Utc;
-
use crate::options;
use crate::raw::*;
+use jiff::Timestamp;
+use std::collections::HashMap;
+use std::time::Duration;
/// Args for `create` operation.
///
@@ -312,8 +309,8 @@ pub struct OpRead {
range: BytesRange,
if_match: Option<String>,
if_none_match: Option<String>,
- if_modified_since: Option<DateTime<Utc>>,
- if_unmodified_since: Option<DateTime<Utc>>,
+ if_modified_since: Option<Timestamp>,
+ if_unmodified_since: Option<Timestamp>,
override_content_type: Option<String>,
override_cache_control: Option<String>,
override_content_disposition: Option<String>,
@@ -399,24 +396,24 @@ impl OpRead {
}
/// Set the If-Modified-Since of the option
- pub fn with_if_modified_since(mut self, v: DateTime<Utc>) -> Self {
+ pub fn with_if_modified_since(mut self, v: Timestamp) -> Self {
self.if_modified_since = Some(v);
self
}
/// Get If-Modified-Since from option
- pub fn if_modified_since(&self) -> Option<DateTime<Utc>> {
+ pub fn if_modified_since(&self) -> Option<Timestamp> {
self.if_modified_since
}
/// Set the If-Unmodified-Since of the option
- pub fn with_if_unmodified_since(mut self, v: DateTime<Utc>) -> Self {
+ pub fn with_if_unmodified_since(mut self, v: Timestamp) -> Self {
self.if_unmodified_since = Some(v);
self
}
/// Get If-Unmodified-Since from option
- pub fn if_unmodified_since(&self) -> Option<DateTime<Utc>> {
+ pub fn if_unmodified_since(&self) -> Option<Timestamp> {
self.if_unmodified_since
}
@@ -562,8 +559,8 @@ impl From<options::ReaderOptions> for (OpRead, OpReader) {
pub struct OpStat {
if_match: Option<String>,
if_none_match: Option<String>,
- if_modified_since: Option<DateTime<Utc>>,
- if_unmodified_since: Option<DateTime<Utc>>,
+ if_modified_since: Option<Timestamp>,
+ if_unmodified_since: Option<Timestamp>,
override_content_type: Option<String>,
override_cache_control: Option<String>,
override_content_disposition: Option<String>,
@@ -599,24 +596,24 @@ impl OpStat {
}
/// Set the If-Modified-Since of the option
- pub fn with_if_modified_since(mut self, v: DateTime<Utc>) -> Self {
+ pub fn with_if_modified_since(mut self, v: Timestamp) -> Self {
self.if_modified_since = Some(v);
self
}
/// Get If-Modified-Since from option
- pub fn if_modified_since(&self) -> Option<DateTime<Utc>> {
+ pub fn if_modified_since(&self) -> Option<Timestamp> {
self.if_modified_since
}
/// Set the If-Unmodified-Since of the option
- pub fn with_if_unmodified_since(mut self, v: DateTime<Utc>) -> Self {
+ pub fn with_if_unmodified_since(mut self, v: Timestamp) -> Self {
self.if_unmodified_since = Some(v);
self
}
/// Get If-Unmodified-Since from option
- pub fn if_unmodified_since(&self) -> Option<DateTime<Utc>> {
+ pub fn if_unmodified_since(&self) -> Option<Timestamp> {
self.if_unmodified_since
}
diff --git a/core/src/raw/std_io_util.rs b/core/src/raw/std_io_util.rs
index 9bb58d3ea..98510d7c5 100644
--- a/core/src/raw/std_io_util.rs
+++ b/core/src/raw/std_io_util.rs
@@ -26,7 +26,7 @@ use crate::*;
/// Add `NotADirectory` and `IsADirectory` once they are stable.
///
/// ref: <https://github.com/rust-lang/rust/issues/86442>
-pub fn new_std_io_error(err: std::io::Error) -> Error {
+pub fn new_std_io_error(err: io::Error) -> Error {
use std::io::ErrorKind::*;
let (kind, retryable) = match err.kind() {
diff --git a/core/src/services/aliyun_drive/backend.rs
b/core/src/services/aliyun_drive/backend.rs
index dfbc03319..828e49404 100644
--- a/core/src/services/aliyun_drive/backend.rs
+++ b/core/src/services/aliyun_drive/backend.rs
@@ -20,9 +20,9 @@ use std::fmt::Formatter;
use std::sync::Arc;
use bytes::Buf;
-use chrono::Utc;
use http::Response;
use http::StatusCode;
+use jiff::Timestamp;
use log::debug;
use tokio::sync::Mutex;
@@ -325,22 +325,18 @@ impl Access for AliyunDriveBackend {
if file.path_type == "folder" {
let meta = Metadata::new(EntryMode::DIR).with_last_modified(
- file.updated_at
- .parse::<chrono::DateTime<Utc>>()
- .map_err(|e| {
- Error::new(ErrorKind::Unexpected, "parse last modified
time").set_source(e)
- })?,
+ file.updated_at.parse::<Timestamp>().map_err(|e| {
+ Error::new(ErrorKind::Unexpected, "parse last modified
time").set_source(e)
+ })?,
);
return Ok(RpStat::new(meta));
}
let mut meta = Metadata::new(EntryMode::FILE).with_last_modified(
- file.updated_at
- .parse::<chrono::DateTime<Utc>>()
- .map_err(|e| {
- Error::new(ErrorKind::Unexpected, "parse last modified
time").set_source(e)
- })?,
+ file.updated_at.parse::<Timestamp>().map_err(|e| {
+ Error::new(ErrorKind::Unexpected, "parse last modified
time").set_source(e)
+ })?,
);
if let Some(v) = file.size {
meta = meta.with_content_length(v);
diff --git a/core/src/services/aliyun_drive/core.rs
b/core/src/services/aliyun_drive/core.rs
index 7f2cedfa1..3459c2ffc 100644
--- a/core/src/services/aliyun_drive/core.rs
+++ b/core/src/services/aliyun_drive/core.rs
@@ -19,12 +19,12 @@ use std::fmt::Debug;
use std::sync::Arc;
use bytes::Buf;
-use chrono::Utc;
use http::Method;
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 +145,14 @@ impl AliyunDriveCore {
access_token,
expire_at,
) => {
- if *expire_at < Utc::now().timestamp() ||
access_token.is_none() {
+ if *expire_at < Timestamp::now().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 + Utc::now().timestamp();
+ *expire_at = output.expires_in +
Timestamp::now().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 ed043a6bc..af61b79fe 100644
--- a/core/src/services/aliyun_drive/lister.rs
+++ b/core/src/services/aliyun_drive/lister.rs
@@ -17,9 +17,6 @@
use std::sync::Arc;
-use bytes::Buf;
-use chrono::Utc;
-
use self::oio::Entry;
use super::core::AliyunDriveCore;
use super::core::AliyunDriveFileList;
@@ -29,6 +26,8 @@ use crate::ErrorKind;
use crate::Metadata;
use crate::Result;
use crate::raw::*;
+use bytes::Buf;
+use jiff::Timestamp;
pub struct AliyunDriveLister {
core: Arc<AliyunDriveCore>,
@@ -69,13 +68,9 @@ impl oio::PageList for AliyunDriveLister {
ctx.entries.push_back(Entry::new(
&parent.path,
Metadata::new(EntryMode::DIR).with_last_modified(
- parent
- .updated_at
- .parse::<chrono::DateTime<Utc>>()
- .map_err(|e| {
- Error::new(ErrorKind::Unexpected, "parse last
modified time")
- .set_source(e)
- })?,
+ parent.updated_at.parse::<Timestamp>().map_err(|e| {
+ Error::new(ErrorKind::Unexpected, "parse last modified
time").set_source(e)
+ })?,
),
));
None
@@ -109,9 +104,9 @@ impl oio::PageList for AliyunDriveLister {
(path, Metadata::new(EntryMode::FILE))
};
- md =
md.with_last_modified(item.updated_at.parse::<chrono::DateTime<Utc>>().map_err(
- |e| Error::new(ErrorKind::Unexpected, "parse last modified
time").set_source(e),
- )?);
+ md =
md.with_last_modified(item.updated_at.parse::<Timestamp>().map_err(|e| {
+ Error::new(ErrorKind::Unexpected, "parse last modified
time").set_source(e)
+ })?);
if let Some(v) = item.size {
md = md.with_content_length(v);
}
diff --git a/core/src/services/alluxio/core.rs
b/core/src/services/alluxio/core.rs
index 8f9dbbaa7..b9b0590e9 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_from_timestamp_millis(
+ .set_last_modified(parse_datetime_from_timestamp_millis(
file_info.last_modification_time_ms,
)?);
Ok(metadata)
diff --git a/core/src/services/b2/core.rs b/core/src/services/b2/core.rs
index 649842835..e429a29b6 100644
--- a/core/src/services/b2/core.rs
+++ b/core/src/services/b2/core.rs
@@ -21,12 +21,11 @@ use std::sync::Arc;
use std::time::Duration;
use bytes::Buf;
-use chrono::DateTime;
-use chrono::Utc;
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;
@@ -80,7 +79,7 @@ impl B2Core {
let signer = self.signer.read().await;
if !signer.auth_info.authorization_token.is_empty()
- && signer.auth_info.expires_in > Utc::now()
+ && signer.auth_info.expires_in > Timestamp::now()
{
let auth_info = signer.auth_info.clone();
return Ok(auth_info);
@@ -114,8 +113,7 @@ impl B2Core {
api_url: token.api_url.clone(),
download_url: token.download_url.clone(),
// This authorization token is valid for at most 24
hours.
- expires_in: Utc::now()
- + chrono::TimeDelta::try_hours(20).expect("20
hours must be valid"),
+ expires_in: Timestamp::now() + Duration::from_secs(20
* 60 * 60),
};
}
_ => {
@@ -577,8 +575,8 @@ pub struct AuthInfo {
pub api_url: String,
/// The base URL to use for downloading files.
pub download_url: String,
-
- pub expires_in: DateTime<Utc>,
+ /// The time when the authorization token expires.
+ pub expires_in: Timestamp,
}
impl Default for B2Signer {
@@ -591,7 +589,7 @@ impl Default for B2Signer {
authorization_token: String::new(),
api_url: String::new(),
download_url: String::new(),
- expires_in: DateTime::<Utc>::MIN_UTC,
+ expires_in: Timestamp::MIN,
},
}
}
diff --git a/core/src/services/cacache/backend.rs
b/core/src/services/cacache/backend.rs
index c3a9b1911..a2b057e77 100644
--- a/core/src/services/cacache/backend.rs
+++ b/core/src/services/cacache/backend.rs
@@ -15,14 +15,12 @@
// specific language governing permissions and limitations
// under the License.
-use std::fmt::Debug;
-use std::sync::Arc;
-
-use chrono::DateTime;
-
use crate::raw::*;
use crate::services::CacacheConfig;
use crate::*;
+use jiff::Timestamp;
+use std::fmt::Debug;
+use std::sync::Arc;
use super::DEFAULT_SCHEME;
use super::core::CacacheCore;
@@ -109,11 +107,11 @@ impl Access for CacacheAccessor {
Some(meta) => {
let mut md = Metadata::new(EntryMode::FILE);
md.set_content_length(meta.size as u64);
- // Convert u128 milliseconds to DateTime<Utc>
+ // Convert u128 milliseconds to Timestamp
let millis = meta.time;
let secs = (millis / 1000) as i64;
- let nanos = ((millis % 1000) * 1_000_000) as u32;
- if let Some(dt) = DateTime::from_timestamp(secs, nanos) {
+ let nanos = ((millis % 1000) * 1_000_000) as i32;
+ if let Ok(dt) = Timestamp::new(secs, nanos) {
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 782076597..4820182d1 100644
--- a/core/src/services/cloudflare_kv/backend.rs
+++ b/core/src/services/cloudflare_kv/backend.rs
@@ -20,9 +20,6 @@ use std::fmt::Formatter;
use std::sync::Arc;
use std::time::Duration;
-use bytes::Buf;
-use http::StatusCode;
-
use super::DEFAULT_SCHEME;
use crate::ErrorKind;
use crate::raw::*;
@@ -34,6 +31,9 @@ use
crate::services::cloudflare_kv::lister::CloudflareKvLister;
use crate::services::cloudflare_kv::model::*;
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;
@@ -249,7 +249,7 @@ impl Access for CloudflareKvAccessor {
// Create metadata for current directory
let cf_kv_metadata = CfKvMetadata {
etag: build_tmp_path_of(¤t_path),
- last_modified: chrono::Local::now().to_rfc3339(),
+ last_modified: Timestamp::now().to_string(),
content_length: 0,
is_dir: true,
};
@@ -348,7 +348,9 @@ impl Access for CloudflareKvAccessor {
}
// Parse since time once for both time-based conditions
- let last_modified =
chrono::DateTime::parse_from_rfc3339(&metadata.last_modified)
+ let last_modified = metadata
+ .last_modified
+ .parse::<Timestamp>()
.map_err(|_| Error::new(ErrorKind::Unsupported, "invalid since
format"))?;
// Check modified_since condition
@@ -437,7 +439,9 @@ impl Access for CloudflareKvAccessor {
}
// Parse since time once for both time-based conditions
- let last_modified =
chrono::DateTime::parse_from_rfc3339(&metadata.last_modified)
+ let last_modified = metadata
+ .last_modified
+ .parse::<Timestamp>()
.map_err(|_| Error::new(ErrorKind::Unsupported, "invalid since
format"))?;
// Check modified_since condition
diff --git a/core/src/services/cloudflare_kv/writer.rs
b/core/src/services/cloudflare_kv/writer.rs
index b21b7152d..1a3e422bc 100644
--- a/core/src/services/cloudflare_kv/writer.rs
+++ b/core/src/services/cloudflare_kv/writer.rs
@@ -17,13 +17,13 @@
use std::sync::Arc;
-use http::StatusCode;
-
use super::core::CloudflareKvCore;
use super::error::parse_error;
use crate::raw::*;
use crate::services::cloudflare_kv::model::CfKvMetadata;
use crate::*;
+use http::StatusCode;
+use jiff::Timestamp;
pub struct CloudflareWriter {
core: Arc<CloudflareKvCore>,
@@ -40,7 +40,7 @@ impl oio::OneShotWrite for CloudflareWriter {
async fn write_once(&self, bs: Buffer) -> Result<Metadata> {
let cf_kv_metadata = CfKvMetadata {
etag: build_tmp_path_of(&self.path),
- last_modified: chrono::Local::now().to_rfc3339(),
+ last_modified: Timestamp::now().to_string(),
content_length: bs.len(),
is_dir: self.path.ends_with('/'),
};
diff --git a/core/src/services/compfs/backend.rs
b/core/src/services/compfs/backend.rs
index 6fb2a692e..906fcab66 100644
--- a/core/src/services/compfs/backend.rs
+++ b/core/src/services/compfs/backend.rs
@@ -152,7 +152,6 @@ impl Access for CompfsBackend {
async fn stat(&self, path: &str, _: OpStat) -> Result<RpStat> {
let path = self.core.prepare_path(path);
-
let meta = self
.core
.exec(move || async move { compio::fs::metadata(path).await })
@@ -165,11 +164,10 @@ impl Access for CompfsBackend {
} else {
EntryMode::Unknown
};
- let last_mod = meta.modified().map_err(new_std_io_error)?.into();
+ let last_mod =
parse_datetime_from_system_time(meta.modified().map_err(new_std_io_error)?)?;
let ret = Metadata::new(mode)
.with_last_modified(last_mod)
.with_content_length(meta.len());
-
Ok(RpStat::new(ret))
}
diff --git a/core/src/services/dashmap/writer.rs
b/core/src/services/dashmap/writer.rs
index ebc0bf3d2..e641a33b4 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};
+use crate::raw::{OpWrite, oio, parse_datetime_from_system_time};
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(SystemTime::now().into());
+
meta.set_last_modified(parse_datetime_from_system_time(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 599c4be4c..2541dcfab 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_from_timestamp_millis(
+ meta.set_last_modified(parse_datetime_from_timestamp_millis(
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 077c2a658..2f5cc4cb9 100644
--- a/core/src/services/dbfs/lister.rs
+++ b/core/src/services/dbfs/lister.rs
@@ -62,14 +62,14 @@ 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_from_timestamp_millis(
+
meta.set_last_modified(parse_datetime_from_timestamp_millis(
status.modification_time,
)?);
oio::Entry::new(&normalized_path, meta)
}
false => {
let mut meta = Metadata::new(EntryMode::FILE);
-
meta.set_last_modified(parse_datetime_from_from_timestamp_millis(
+
meta.set_last_modified(parse_datetime_from_timestamp_millis(
status.modification_time,
)?);
meta.set_content_length(status.file_size as u64);
diff --git a/core/src/services/dropbox/builder.rs
b/core/src/services/dropbox/builder.rs
index b561047b0..549459f6a 100644
--- a/core/src/services/dropbox/builder.rs
+++ b/core/src/services/dropbox/builder.rs
@@ -15,12 +15,10 @@
// specific language governing permissions and limitations
// under the License.
+use jiff::Timestamp;
use std::fmt::Debug;
use std::fmt::Formatter;
use std::sync::Arc;
-
-use chrono::DateTime;
-use chrono::Utc;
use tokio::sync::Mutex;
use super::DEFAULT_SCHEME;
@@ -135,7 +133,7 @@ impl Builder for DropboxBuilder {
(Some(access_token), None) => DropboxSigner {
access_token,
// We will never expire user specified token.
- expires_in: DateTime::<Utc>::MAX_UTC,
+ expires_in: Timestamp::MAX,
..Default::default()
},
(None, Some(refresh_token)) => {
diff --git a/core/src/services/dropbox/core.rs
b/core/src/services/dropbox/core.rs
index 1f92a5cfd..b6c59978a 100644
--- a/core/src/services/dropbox/core.rs
+++ b/core/src/services/dropbox/core.rs
@@ -15,23 +15,22 @@
// specific language governing permissions and limitations
// under the License.
-use std::default::Default;
-use std::fmt::Debug;
-use std::fmt::Formatter;
-use std::sync::Arc;
-
use bytes::Buf;
use bytes::Bytes;
-use chrono::DateTime;
-use chrono::Utc;
use http::Request;
use http::Response;
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;
+use std::fmt::Debug;
+use std::fmt::Formatter;
+use std::sync::Arc;
+use std::time::Duration;
use tokio::sync::Mutex;
use super::error::parse_error;
@@ -64,7 +63,7 @@ impl DropboxCore {
let mut signer = self.signer.lock().await;
// Access token is valid, use it directly.
- if !signer.access_token.is_empty() && signer.expires_in > Utc::now() {
+ if !signer.access_token.is_empty() && signer.expires_in >
Timestamp::now() {
let value = format!("Bearer {}", signer.access_token)
.parse()
.expect("token must be valid header value");
@@ -97,10 +96,8 @@ impl DropboxCore {
signer.access_token.clone_from(&token.access_token);
// Refresh it 2 minutes earlier.
- signer.expires_in = Utc::now()
- + chrono::TimeDelta::try_seconds(token.expires_in as i64)
- .expect("expires_in must be valid seconds")
- - chrono::TimeDelta::try_seconds(120).expect("120 must be valid
seconds");
+ signer.expires_in =
+ Timestamp::now() + Duration::from_secs(token.expires_in) -
Duration::from_secs(120);
let value = format!("Bearer {}", token.access_token)
.parse()
@@ -343,7 +340,7 @@ pub struct DropboxSigner {
pub refresh_token: String,
pub access_token: String,
- pub expires_in: DateTime<Utc>,
+ pub expires_in: Timestamp,
}
impl Default for DropboxSigner {
@@ -354,7 +351,7 @@ impl Default for DropboxSigner {
client_secret: String::new(),
access_token: String::new(),
- expires_in: DateTime::<Utc>::MIN_UTC,
+ expires_in: Timestamp::MIN,
}
}
}
@@ -430,7 +427,7 @@ struct DropboxMetadataArgs {
#[derive(Clone, Deserialize)]
struct DropboxTokenResponse {
access_token: String,
- expires_in: usize,
+ expires_in: u64,
}
#[derive(Default, Debug, Deserialize)]
diff --git a/core/src/services/fs/core.rs b/core/src/services/fs/core.rs
index 822cb42b3..46d731eef 100644
--- a/core/src/services/fs/core.rs
+++ b/core/src/services/fs/core.rs
@@ -20,8 +20,6 @@ use std::path::Path;
use std::path::PathBuf;
use std::sync::Arc;
-use chrono::DateTime;
-
use super::error::*;
use crate::raw::*;
use crate::*;
@@ -74,7 +72,6 @@ impl FsCore {
pub async fn fs_stat(&self, path: &str) -> Result<Metadata> {
let p = self.root.join(path.trim_end_matches('/'));
let meta = tokio::fs::metadata(&p).await.map_err(new_std_io_error)?;
-
let mode = if meta.is_dir() {
EntryMode::DIR
} else if meta.is_file() {
@@ -84,12 +81,9 @@ impl FsCore {
};
let m = Metadata::new(mode)
.with_content_length(meta.len())
- .with_last_modified(
- meta.modified()
- .map(DateTime::from)
- .map_err(new_std_io_error)?,
- );
-
+ .with_last_modified(parse_datetime_from_system_time(
+ 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 ff4e3ba34..38c4c2f3e 100644
--- a/core/src/services/fs/writer.rs
+++ b/core/src/services/fs/writer.rs
@@ -107,7 +107,9 @@ 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(file_meta.modified().map_err(new_std_io_error)?.into());
+ .with_last_modified(parse_datetime_from_system_time(
+ file_meta.modified().map_err(new_std_io_error)?,
+ )?);
Ok(meta)
}
@@ -181,7 +183,9 @@ impl oio::PositionWrite for FsWriter {
};
let meta = Metadata::new(mode)
.with_content_length(file_meta.len())
-
.with_last_modified(file_meta.modified().map_err(new_std_io_error)?.into());
+ .with_last_modified(parse_datetime_from_system_time(
+ 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 ee942f9a1..660e6e873 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(file.modified().into());
+
meta.set_last_modified(parse_datetime_from_system_time(file.modified())?);
Ok(RpStat::new(meta))
}
diff --git a/core/src/services/ftp/lister.rs b/core/src/services/ftp/lister.rs
index 6dedc8f45..a7fd77085 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(de.modified().into());
+
meta.set_last_modified(parse_datetime_from_system_time(de.modified())?);
let entry = if de.is_file() {
oio::Entry::new(&path, meta)
diff --git a/core/src/services/gdrive/backend.rs
b/core/src/services/gdrive/backend.rs
index 777e06887..df5bc659c 100644
--- a/core/src/services/gdrive/backend.rs
+++ b/core/src/services/gdrive/backend.rs
@@ -18,11 +18,6 @@
use std::fmt::Debug;
use std::sync::Arc;
-use bytes::Buf;
-use chrono::Utc;
-use http::Response;
-use http::StatusCode;
-
use super::core::GdriveCore;
use super::core::GdriveFile;
use super::delete::GdriveDeleter;
@@ -31,6 +26,10 @@ use super::lister::GdriveLister;
use super::writer::GdriveWriter;
use crate::raw::*;
use crate::*;
+use bytes::Buf;
+use http::Response;
+use http::StatusCode;
+use jiff::Timestamp;
#[derive(Clone, Debug)]
pub struct GdriveBackend {
@@ -77,7 +76,7 @@ impl Access for GdriveBackend {
})?);
}
if let Some(v) = gdrive_file.modified_time {
- meta =
meta.with_last_modified(v.parse::<chrono::DateTime<Utc>>().map_err(|e| {
+ meta = meta.with_last_modified(v.parse::<Timestamp>().map_err(|e| {
Error::new(ErrorKind::Unexpected, "parse last modified
time").set_source(e)
})?);
}
diff --git a/core/src/services/gdrive/builder.rs
b/core/src/services/gdrive/builder.rs
index ea985df3b..dc5a0946b 100644
--- a/core/src/services/gdrive/builder.rs
+++ b/core/src/services/gdrive/builder.rs
@@ -15,13 +15,11 @@
// specific language governing permissions and limitations
// under the License.
+use jiff::Timestamp;
+use log::debug;
use std::fmt::Debug;
use std::fmt::Formatter;
use std::sync::Arc;
-
-use chrono::DateTime;
-use chrono::Utc;
-use log::debug;
use tokio::sync::Mutex;
use super::DEFAULT_SCHEME;
@@ -175,7 +173,7 @@ impl Builder for GdriveBuilder {
(Some(access_token), None) => {
signer.access_token = access_token;
// We will never expire user specified access token.
- signer.expires_in = DateTime::<Utc>::MAX_UTC;
+ signer.expires_in = Timestamp::MAX;
}
(None, Some(refresh_token)) => {
let client_id = self.config.client_id.ok_or_else(|| {
diff --git a/core/src/services/gdrive/core.rs b/core/src/services/gdrive/core.rs
index e59914e70..82354dd67 100644
--- a/core/src/services/gdrive/core.rs
+++ b/core/src/services/gdrive/core.rs
@@ -15,21 +15,20 @@
// specific language governing permissions and limitations
// under the License.
-use std::fmt::Debug;
-use std::fmt::Formatter;
-use std::sync::Arc;
-
use bytes;
use bytes::Buf;
use bytes::Bytes;
-use chrono::DateTime;
-use chrono::Utc;
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;
+use std::fmt::Formatter;
+use std::sync::Arc;
+use std::time::Duration;
use tokio::sync::Mutex;
use super::error::parse_error;
@@ -304,7 +303,7 @@ pub struct GdriveSigner {
pub refresh_token: String,
pub access_token: String,
- pub expires_in: DateTime<Utc>,
+ pub expires_in: Timestamp,
}
impl GdriveSigner {
@@ -317,13 +316,13 @@ impl GdriveSigner {
client_secret: "".to_string(),
refresh_token: "".to_string(),
access_token: "".to_string(),
- expires_in: DateTime::<Utc>::MIN_UTC,
+ expires_in: Timestamp::MIN,
}
}
/// Sign a request.
pub async fn sign<T>(&mut self, req: &mut Request<T>) -> Result<()> {
- if !self.access_token.is_empty() && self.expires_in > Utc::now() {
+ if !self.access_token.is_empty() && self.expires_in > Timestamp::now()
{
let value = format!("Bearer {}", self.access_token)
.parse()
.expect("access token must be valid header value");
@@ -352,10 +351,8 @@ impl GdriveSigner {
let token: GdriveTokenResponse =
serde_json::from_reader(resp_body.reader())
.map_err(new_json_deserialize_error)?;
self.access_token.clone_from(&token.access_token);
- self.expires_in = Utc::now()
- + chrono::TimeDelta::try_seconds(token.expires_in)
- .expect("expires_in must be valid seconds")
- - chrono::TimeDelta::try_seconds(120).expect("120 must
be valid seconds");
+ self.expires_in = Timestamp::now() +
Duration::from_secs(token.expires_in)
+ - Duration::from_secs(120);
}
_ => {
return Err(parse_error(resp));
@@ -469,7 +466,7 @@ impl PathQuery for GdrivePathQuery {
#[derive(Deserialize)]
pub struct GdriveTokenResponse {
access_token: String,
- expires_in: i64,
+ expires_in: u64,
}
/// This is the file struct returned by the Google Drive API.
diff --git a/core/src/services/github/core.rs b/core/src/services/github/core.rs
index 37b496b60..944cd0fd9 100644
--- a/core/src/services/github/core.rs
+++ b/core/src/services/github/core.rs
@@ -27,6 +27,7 @@ use http::Response;
use http::StatusCode;
use http::header;
use http::request;
+use jiff::Timestamp;
use serde::Deserialize;
use serde::Serialize;
@@ -174,7 +175,7 @@ impl GithubCore {
let req = self.sign(req)?;
let mut req_body = CreateOrUpdateContentsRequest {
- message: format!("Write {} at {} via opendal", path,
chrono::Local::now()),
+ message: format!("Write {} at {} via opendal", path,
Timestamp::now()),
content:
base64::engine::general_purpose::STANDARD.encode(bs.to_bytes()),
sha: None,
};
@@ -222,7 +223,7 @@ impl GithubCore {
let req = self.sign(req)?;
let req_body = DeleteContentsRequest {
- message: format!("Delete {} at {} via opendal", path,
chrono::Local::now()),
+ message: format!("Delete {} at {} via opendal", path,
Timestamp::now()),
sha,
};
diff --git a/core/src/services/hdfs/backend.rs
b/core/src/services/hdfs/backend.rs
index 083e1a762..22555cee2 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(meta.modified().into());
+ m.set_last_modified(parse_datetime_from_system_time(meta.modified())?);
Ok(RpStat::new(m))
}
diff --git a/core/src/services/hdfs/lister.rs b/core/src/services/hdfs/lister.rs
index 60f53c1b7..7d83ead57 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(de.modified().into());
+
.with_last_modified(parse_datetime_from_system_time(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 dd69c344e..39c41824d 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_from_timestamp_millis(
+ .set_last_modified(parse_datetime_from_timestamp_millis(
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 21bda41bf..af18b658d 100644
--- a/core/src/services/hdfs_native/lister.rs
+++ b/core/src/services/hdfs_native/lister.rs
@@ -22,7 +22,7 @@ use crate::Metadata;
use crate::Result;
use crate::raw::build_rel_path;
use crate::raw::oio;
-use crate::raw::parse_datetime_from_from_timestamp_millis;
+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_from_timestamp_millis(
+
.with_last_modified(parse_datetime_from_timestamp_millis(
status.modification_time as i64,
)?);
oio::Entry::new(&path, meta)
diff --git a/core/src/services/koofr/backend.rs
b/core/src/services/koofr/backend.rs
index 1458504d5..a56cf7b85 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_from_timestamp_millis(file.modified)?);
+
.set_last_modified(parse_datetime_from_timestamp_millis(file.modified)?);
Ok(RpStat::new(md))
}
diff --git a/core/src/services/koofr/lister.rs
b/core/src/services/koofr/lister.rs
index 8369c62ec..88642aa78 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_from_timestamp_millis(file.modified)?);
+
.with_last_modified(parse_datetime_from_timestamp_millis(file.modified)?);
Entry::new(&path, m)
};
diff --git a/core/src/services/lakefs/backend.rs
b/core/src/services/lakefs/backend.rs
index 1c1613c20..f4802e843 100644
--- a/core/src/services/lakefs/backend.rs
+++ b/core/src/services/lakefs/backend.rs
@@ -20,10 +20,9 @@ use std::fmt::Formatter;
use std::sync::Arc;
use bytes::Buf;
-use chrono::TimeZone;
-use chrono::Utc;
use http::Response;
use http::StatusCode;
+use jiff::Timestamp;
use log::debug;
use super::DEFAULT_SCHEME;
@@ -242,7 +241,7 @@ impl Access for LakefsBackend {
meta.set_content_disposition(v);
}
-
meta.set_last_modified(Utc.timestamp_opt(decoded_response.mtime, 0).unwrap());
+
meta.set_last_modified(Timestamp::from_second(decoded_response.mtime).unwrap());
Ok(RpStat::new(meta))
}
diff --git a/core/src/services/lakefs/lister.rs
b/core/src/services/lakefs/lister.rs
index 3dc426384..e73a26473 100644
--- a/core/src/services/lakefs/lister.rs
+++ b/core/src/services/lakefs/lister.rs
@@ -17,15 +17,13 @@
use std::sync::Arc;
-use bytes::Buf;
-use chrono::TimeZone;
-use chrono::Utc;
-
use super::core::LakefsCore;
use super::core::LakefsListResponse;
use super::error::parse_error;
use crate::raw::*;
use crate::*;
+use bytes::Buf;
+use jiff::Timestamp;
pub struct LakefsLister {
core: Arc<LakefsCore>,
@@ -94,7 +92,7 @@ impl oio::PageList for LakefsLister {
let mut meta = Metadata::new(entry_type);
if status.mtime != 0 {
- meta.set_last_modified(Utc.timestamp_opt(status.mtime,
0).unwrap());
+
meta.set_last_modified(Timestamp::from_second(status.mtime).unwrap());
}
if entry_type == EntryMode::FILE {
diff --git a/core/src/services/mini_moka/writer.rs
b/core/src/services/mini_moka/writer.rs
index a751d444b..5e5c12b13 100644
--- a/core/src/services/mini_moka/writer.rs
+++ b/core/src/services/mini_moka/writer.rs
@@ -15,12 +15,12 @@
// specific language governing permissions and limitations
// under the License.
-use std::sync::Arc;
-
use super::core::{MiniMokaCore, MiniMokaValue};
use crate::raw::oio;
use crate::raw::*;
use crate::*;
+use jiff::Timestamp;
+use std::sync::Arc;
pub struct MiniMokaWriter {
core: Arc<MiniMokaCore>,
@@ -51,7 +51,7 @@ impl oio::Write for MiniMokaWriter {
let mut md = Metadata::new(EntryMode::from_path(&self.path));
md.set_content_length(buf.len() as u64);
- md.set_last_modified(chrono::Utc::now());
+ md.set_last_modified(Timestamp::now());
// Set metadata from OpWrite
if let Some(content_type) = self.op.content_type() {
diff --git a/core/src/services/monoiofs/backend.rs
b/core/src/services/monoiofs/backend.rs
index 114ed1907..217714217 100644
--- a/core/src/services/monoiofs/backend.rs
+++ b/core/src/services/monoiofs/backend.rs
@@ -15,14 +15,12 @@
// specific language governing permissions and limitations
// under the License.
+use monoio::fs::OpenOptions;
use std::fmt::Debug;
use std::io;
use std::path::PathBuf;
use std::sync::Arc;
-use chrono::DateTime;
-use monoio::fs::OpenOptions;
-
use super::core::BUFFER_SIZE;
use super::core::MonoiofsCore;
use super::delete::MonoiofsDeleter;
@@ -126,11 +124,9 @@ impl Access for MonoiofsBackend {
};
let m = Metadata::new(mode)
.with_content_length(meta.len())
- .with_last_modified(
- meta.modified()
- .map(DateTime::from)
- .map_err(new_std_io_error)?,
- );
+ .with_last_modified(parse_datetime_from_system_time(
+ 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 df0272a8a..e4172e561 100644
--- a/core/src/services/monoiofs/writer.rs
+++ b/core/src/services/monoiofs/writer.rs
@@ -20,7 +20,6 @@ use std::sync::Arc;
use bytes::Buf;
use bytes::Bytes;
-use chrono::DateTime;
use futures::SinkExt;
use futures::StreamExt;
use futures::channel::mpsc;
@@ -171,12 +170,9 @@ impl oio::Write for MonoiofsWriter {
};
let meta = Metadata::new(mode)
.with_content_length(file_meta.len())
- .with_last_modified(
- file_meta
- .modified()
- .map(DateTime::from)
- .map_err(new_std_io_error)?,
- );
+ .with_last_modified(parse_datetime_from_system_time(
+ 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 d8e5071a6..35be2cbbb 100644
--- a/core/src/services/onedrive/builder.rs
+++ b/core/src/services/onedrive/builder.rs
@@ -15,15 +15,13 @@
// specific language governing permissions and limitations
// under the License.
-use std::fmt::Debug;
-use std::fmt::Formatter;
-use std::sync::Arc;
-
-use chrono::DateTime;
-use chrono::Utc;
+use jiff::Timestamp;
use log::debug;
use services::onedrive::core::OneDriveCore;
use services::onedrive::core::OneDriveSigner;
+use std::fmt::Debug;
+use std::fmt::Formatter;
+use std::sync::Arc;
use tokio::sync::Mutex;
use super::DEFAULT_SCHEME;
@@ -192,7 +190,7 @@ impl Builder for OnedriveBuilder {
match (self.config.access_token, self.config.refresh_token) {
(Some(access_token), None) => {
signer.access_token = access_token;
- signer.expires_in = DateTime::<Utc>::MAX_UTC;
+ signer.expires_in = Timestamp::MAX;
}
(None, Some(refresh_token)) => {
let client_id = self.config.client_id.ok_or_else(|| {
diff --git a/core/src/services/onedrive/core.rs
b/core/src/services/onedrive/core.rs
index d62e88d96..07cb7746c 100644
--- a/core/src/services/onedrive/core.rs
+++ b/core/src/services/onedrive/core.rs
@@ -22,12 +22,11 @@ use std::time::Duration;
use bytes::Buf;
use bytes::Bytes;
-use chrono::DateTime;
-use chrono::Utc;
use http::Request;
use http::Response;
use http::StatusCode;
use http::header;
+use jiff::Timestamp;
use tokio::sync::Mutex;
use super::error::parse_error;
@@ -55,7 +54,8 @@ const SPECIAL_POSIX_ENTRIES: [&str; 3] = [".", "/", ""];
// organizes a few core module functions
impl OneDriveCore {
// OneDrive personal's base URL. `me` is an alias that represents the
user's "Drive".
- pub(crate) const DRIVE_ROOT_URL: &str =
"https://graph.microsoft.com/v1.0/me/drive/root";
+ pub(crate) const DRIVE_ROOT_URL: &'static str =
+ "https://graph.microsoft.com/v1.0/me/drive/root";
/// Get a URL to an OneDrive item
pub(crate) fn onedrive_item_url(&self, path: &str, build_absolute_path:
bool) -> String {
@@ -608,7 +608,7 @@ pub struct OneDriveSigner {
pub refresh_token: String,
pub access_token: String,
- pub expires_in: DateTime<Utc>,
+ pub expires_in: Timestamp,
}
// OneDrive is part of Graph API hence shares the same authentication and
authorization processes.
@@ -629,7 +629,7 @@ impl OneDriveSigner {
client_secret: "".to_string(),
refresh_token: "".to_string(),
access_token: "".to_string(),
- expires_in: DateTime::<Utc>::MIN_UTC,
+ expires_in: Timestamp::MIN,
}
}
@@ -655,10 +655,8 @@ impl OneDriveSigner {
.map_err(new_json_deserialize_error)?;
self.access_token = data.access_token;
self.refresh_token = data.refresh_token;
- self.expires_in = Utc::now()
- + chrono::TimeDelta::try_seconds(data.expires_in)
- .expect("expires_in must be valid seconds")
- - chrono::TimeDelta::minutes(2); // assumes 2 mins
graceful transmission for implementation simplicity
+ self.expires_in = Timestamp::now() +
Duration::from_secs(data.expires_in)
+ - Duration::from_secs(120); // assumes 2 mins graceful
transmission for implementation simplicity
Ok(())
}
_ => Err(parse_error(response)),
@@ -667,7 +665,7 @@ impl OneDriveSigner {
/// Sign a request.
pub async fn sign<T>(&mut self, request: &mut Request<T>) -> Result<()> {
- if !self.access_token.is_empty() && self.expires_in > Utc::now() {
+ if !self.access_token.is_empty() && self.expires_in > Timestamp::now()
{
let value = format!("Bearer {}", self.access_token)
.parse()
.expect("access_token must be valid header value");
diff --git a/core/src/services/onedrive/graph_model.rs
b/core/src/services/onedrive/graph_model.rs
index 87a98b077..3fe407c0a 100644
--- a/core/src/services/onedrive/graph_model.rs
+++ b/core/src/services/onedrive/graph_model.rs
@@ -22,7 +22,7 @@ use serde::Serialize;
pub struct GraphOAuthRefreshTokenResponseBody {
pub access_token: String,
pub refresh_token: String,
- pub expires_in: i64, // in seconds
+ pub expires_in: u64, // in seconds
}
/// We `$select` some fields when sending GET requests.
diff --git a/core/src/services/seafile/lister.rs
b/core/src/services/seafile/lister.rs
index 58d948b82..e1720cde9 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_from_timestamp(info.mtime)?)
+
.with_last_modified(parse_datetime_from_timestamp(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 f30c84233..96f9fa9a1 100644
--- a/core/src/services/sftp/utils.rs
+++ b/core/src/services/sftp/utils.rs
@@ -19,6 +19,7 @@ use openssh_sftp_client::metadata::MetaData as SftpMeta;
use crate::EntryMode;
use crate::Metadata;
+use crate::raw::parse_datetime_from_system_time;
/// REMOVE ME: we should not implement `From<SftpMeta> for Metadata`.
impl From<SftpMeta> for Metadata {
@@ -43,7 +44,9 @@ impl From<SftpMeta> for Metadata {
}
if let Some(modified) = meta.modified() {
- metadata.set_last_modified(modified.as_system_time().into());
+ if let Ok(m) =
parse_datetime_from_system_time(modified.as_system_time()) {
+ metadata.set_last_modified(m);
+ }
}
metadata
diff --git a/core/src/services/upyun/core.rs b/core/src/services/upyun/core.rs
index b6dc4c2ee..881fdf2d5 100644
--- a/core/src/services/upyun/core.rs
+++ b/core/src/services/upyun/core.rs
@@ -26,6 +26,7 @@ use http::HeaderMap;
use http::Request;
use http::Response;
use http::header;
+use jiff::Timestamp;
use md5::Digest;
use serde::Deserialize;
use sha1::Sha1;
@@ -86,8 +87,8 @@ impl UpyunCore {
pub fn sign(&self, req: &mut Request<Buffer>) -> Result<()> {
// get rfc1123 date
- let date = chrono::Utc::now()
- .format("%a, %d %b %Y %H:%M:%S GMT")
+ let date = Timestamp::now()
+ .strftime("%a, %d %b %Y %H:%M:%S GMT")
.to_string();
let authorization =
self.signer
diff --git a/core/src/services/upyun/lister.rs
b/core/src/services/upyun/lister.rs
index b93687c18..d86249bc4 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_from_timestamp(file.last_modified)?);
+
.with_last_modified(parse_datetime_from_timestamp(file.last_modified)?);
Entry::new(&path, m)
};
diff --git a/core/src/services/webhdfs/backend.rs
b/core/src/services/webhdfs/backend.rs
index 38503ef1a..3ec8cba29 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_from_timestamp_millis(
+
.with_last_modified(parse_datetime_from_timestamp_millis(
file_status.modification_time,
)?),
};
diff --git a/core/src/services/webhdfs/lister.rs
b/core/src/services/webhdfs/lister.rs
index 1d8228d79..dae855e79 100644
--- a/core/src/services/webhdfs/lister.rs
+++ b/core/src/services/webhdfs/lister.rs
@@ -110,7 +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_from_timestamp_millis(
+ .with_last_modified(parse_datetime_from_timestamp_millis(
status.modification_time,
)?),
};
diff --git a/core/src/types/metadata.rs b/core/src/types/metadata.rs
index fab17dbeb..d09a481fe 100644
--- a/core/src/types/metadata.rs
+++ b/core/src/types/metadata.rs
@@ -15,12 +15,10 @@
// specific language governing permissions and limitations
// under the License.
-use std::collections::HashMap;
-
-use chrono::prelude::*;
-
use crate::raw::*;
use crate::*;
+use jiff::Timestamp;
+use std::collections::HashMap;
/// Metadata contains all the information related to a specific path.
///
@@ -62,7 +60,7 @@ pub struct Metadata {
content_type: Option<String>,
content_encoding: Option<String>,
etag: Option<String>,
- last_modified: Option<DateTime<Utc>>,
+ last_modified: Option<Timestamp>,
version: Option<String>,
user_metadata: Option<HashMap<String, String>>,
@@ -321,18 +319,18 @@ impl Metadata {
/// `Last-Modified` is defined by [RFC
7232](https://httpwg.org/specs/rfc7232.html#header.last-modified)
///
/// Refer to [MDN
Last-Modified](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified)
for more information.
- pub fn last_modified(&self) -> Option<DateTime<Utc>> {
+ pub fn last_modified(&self) -> Option<Timestamp> {
self.last_modified
}
/// Set Last modified of this entry.
- pub fn set_last_modified(&mut self, v: DateTime<Utc>) -> &mut Self {
+ pub fn set_last_modified(&mut self, v: Timestamp) -> &mut Self {
self.last_modified = Some(v);
self
}
/// Set Last modified of this entry.
- pub fn with_last_modified(mut self, v: DateTime<Utc>) -> Self {
+ pub fn with_last_modified(mut self, v: Timestamp) -> Self {
self.last_modified = Some(v);
self
}
diff --git a/core/src/types/operator/operator_futures.rs
b/core/src/types/operator/operator_futures.rs
index 1fcb46e25..f761316b2 100644
--- a/core/src/types/operator/operator_futures.rs
+++ b/core/src/types/operator/operator_futures.rs
@@ -24,12 +24,10 @@ use std::future::IntoFuture;
use std::ops::RangeBounds;
use std::time::Duration;
-use chrono::DateTime;
-use chrono::Utc;
-use futures::Future;
-
use crate::raw::*;
use crate::*;
+use futures::Future;
+use jiff::Timestamp;
/// OperatorFuture is the future generated by [`Operator`].
///
@@ -107,7 +105,7 @@ impl<F: Future<Output = Result<Metadata>>> FutureStat<F> {
/// Set the If-Modified-Since for this operation.
///
/// Refer to [`options::StatOptions::if_modified_since`] for more details.
- pub fn if_modified_since(mut self, v: DateTime<Utc>) -> Self {
+ pub fn if_modified_since(mut self, v: Timestamp) -> Self {
self.args.if_modified_since = Some(v);
self
}
@@ -115,7 +113,7 @@ impl<F: Future<Output = Result<Metadata>>> FutureStat<F> {
/// Set the If-Unmodified-Since for this operation.
///
/// Refer to [`options::StatOptions::if_unmodified_since`] for more
details.
- pub fn if_unmodified_since(mut self, v: DateTime<Utc>) -> Self {
+ pub fn if_unmodified_since(mut self, v: Timestamp) -> Self {
self.args.if_unmodified_since = Some(v);
self
}
@@ -385,15 +383,14 @@ impl<F: Future<Output = Result<Buffer>>> FutureRead<F> {
///
/// ```
/// # use opendal::Result;
- /// use chrono::DateTime;
- /// use chrono::Utc;
+ /// use jiff::Timestamp;
/// use opendal::Operator;
- /// # async fn test(op: Operator, time: DateTime<Utc>) -> Result<()> {
+ /// # async fn test(op: Operator, time: Timestamp) -> Result<()> {
/// let mut metadata =
op.read_with("path/to/file").if_modified_since(time).await?;
/// # Ok(())
/// # }
/// ```
- pub fn if_modified_since(mut self, v: DateTime<Utc>) -> Self {
+ pub fn if_modified_since(mut self, v: Timestamp) -> Self {
self.args.if_modified_since = Some(v);
self
}
@@ -407,10 +404,9 @@ impl<F: Future<Output = Result<Buffer>>> FutureRead<F> {
///
/// ```
/// # use opendal::Result;
- /// use chrono::DateTime;
- /// use chrono::Utc;
+ /// use jiff::Timestamp;
/// use opendal::Operator;
- /// # async fn test(op: Operator, time: DateTime<Utc>) -> Result<()> {
+ /// # async fn test(op: Operator, time: Timestamp) -> Result<()> {
/// let mut metadata = op
/// .read_with("path/to/file")
/// .if_unmodified_since(time)
@@ -418,7 +414,7 @@ impl<F: Future<Output = Result<Buffer>>> FutureRead<F> {
/// # Ok(())
/// # }
/// ```
- pub fn if_unmodified_since(mut self, v: DateTime<Utc>) -> Self {
+ pub fn if_unmodified_since(mut self, v: Timestamp) -> Self {
self.args.if_unmodified_since = Some(v);
self
}
@@ -579,10 +575,9 @@ impl<F: Future<Output = Result<Reader>>> FutureReader<F> {
///
/// ```
/// # use opendal::Result;
- /// use chrono::DateTime;
- /// use chrono::Utc;
+ /// use jiff::Timestamp;
/// use opendal::Operator;
- /// # async fn test(op: Operator, time: DateTime<Utc>) -> Result<()> {
+ /// # async fn test(op: Operator, time: Timestamp) -> Result<()> {
/// let mut r = op
/// .reader_with("path/to/file")
/// .if_modified_since(time)
@@ -590,7 +585,7 @@ impl<F: Future<Output = Result<Reader>>> FutureReader<F> {
/// # Ok(())
/// # }
/// ```
- pub fn if_modified_since(mut self, v: DateTime<Utc>) -> Self {
+ pub fn if_modified_since(mut self, v: Timestamp) -> Self {
self.args.if_modified_since = Some(v);
self
}
@@ -604,10 +599,9 @@ impl<F: Future<Output = Result<Reader>>> FutureReader<F> {
///
/// ```
/// # use opendal::Result;
- /// use chrono::DateTime;
- /// use chrono::Utc;
+ /// use jiff::Timestamp;
/// use opendal::Operator;
- /// # async fn test(op: Operator, time: DateTime<Utc>) -> Result<()> {
+ /// # async fn test(op: Operator, time: Timestamp) -> Result<()> {
/// let mut r = op
/// .reader_with("path/to/file")
/// .if_unmodified_since(time)
@@ -615,7 +609,7 @@ impl<F: Future<Output = Result<Reader>>> FutureReader<F> {
/// # Ok(())
/// # }
/// ```
- pub fn if_unmodified_since(mut self, v: DateTime<Utc>) -> Self {
+ pub fn if_unmodified_since(mut self, v: Timestamp) -> Self {
self.args.if_unmodified_since = Some(v);
self
}
diff --git a/core/src/types/options.rs b/core/src/types/options.rs
index 81863366d..e754e6d40 100644
--- a/core/src/types/options.rs
+++ b/core/src/types/options.rs
@@ -17,12 +17,9 @@
//! Options module provides options definitions for operations.
-use std::collections::HashMap;
-
-use chrono::DateTime;
-use chrono::Utc;
-
use crate::raw::BytesRange;
+use jiff::Timestamp;
+use std::collections::HashMap;
/// Options for delete operations.
#[derive(Debug, Clone, Default, Eq, PartialEq)]
@@ -108,14 +105,14 @@ pub struct ReadOptions {
///
/// If file exists and it hasn't been modified since the specified time,
an error with kind
/// [`ErrorKind::ConditionNotMatch`] will be returned.
- pub if_modified_since: Option<DateTime<Utc>>,
+ pub if_modified_since: Option<Timestamp>,
/// Set `if_unmodified_since` for this operation.
///
/// This feature can be used to check if the file hasn't been modified
since the given timestamp.
///
/// If file exists and it has been modified since the specified time, an
error with kind
/// [`ErrorKind::ConditionNotMatch`] will be returned.
- pub if_unmodified_since: Option<DateTime<Utc>>,
+ pub if_unmodified_since: Option<Timestamp>,
/// Set `concurrent` for the operation.
///
@@ -192,14 +189,14 @@ pub struct ReaderOptions {
///
/// If file exists and it hasn't been modified since the specified time,
an error with kind
/// [`ErrorKind::ConditionNotMatch`] will be returned.
- pub if_modified_since: Option<DateTime<Utc>>,
+ pub if_modified_since: Option<Timestamp>,
/// Set `if_unmodified_since` for this operation.
///
/// This feature can be used to check if the file hasn't been modified
since the given timestamp.
///
/// If file exists and it has been modified since the specified time, an
error with kind
/// [`ErrorKind::ConditionNotMatch`] will be returned.
- pub if_unmodified_since: Option<DateTime<Utc>>,
+ pub if_unmodified_since: Option<Timestamp>,
/// Set `concurrent` for the operation.
///
@@ -277,14 +274,14 @@ pub struct StatOptions {
///
/// If file exists and it hasn't been modified since the specified time,
an error with kind
/// [`ErrorKind::ConditionNotMatch`] will be returned.
- pub if_modified_since: Option<DateTime<Utc>>,
+ pub if_modified_since: Option<Timestamp>,
/// Set `if_unmodified_since` for this operation.
///
/// This feature can be used to check if the file hasn't been modified
since the given timestamp.
///
/// If file exists and it has been modified since the specified time, an
error with kind
/// [`ErrorKind::ConditionNotMatch`] will be returned.
- pub if_unmodified_since: Option<DateTime<Utc>>,
+ pub if_unmodified_since: Option<Timestamp>,
/// Specify the content-type header that should be sent back by the
operation.
///
diff --git a/core/tests/behavior/async_read.rs
b/core/tests/behavior/async_read.rs
index e79f3b22f..78c5eff23 100644
--- a/core/tests/behavior/async_read.rs
+++ b/core/tests/behavior/async_read.rs
@@ -288,14 +288,14 @@ pub async fn test_reader_with_if_modified_since(op:
Operator) -> anyhow::Result<
.expect("write must succeed");
let last_modified_time = op.stat(&path).await?.last_modified().unwrap();
- let since = last_modified_time - chrono::Duration::seconds(1);
+ let since = last_modified_time - Duration::from_secs(1);
let reader = op.reader_with(&path).if_modified_since(since).await?;
let bs = reader.read(..).await?.to_bytes();
assert_eq!(bs, content);
sleep(Duration::from_secs(1)).await;
- let since = last_modified_time + chrono::Duration::seconds(1);
+ let since = last_modified_time + Duration::from_secs(1);
let reader = op.reader_with(&path).if_modified_since(since).await?;
let res = reader.read(..).await;
assert!(res.is_err());
@@ -317,7 +317,7 @@ pub async fn test_reader_with_if_unmodified_since(op:
Operator) -> anyhow::Resul
.expect("write must succeed");
let last_modified_time = op.stat(&path).await?.last_modified().unwrap();
- let since = last_modified_time - chrono::Duration::seconds(1);
+ let since = last_modified_time - Duration::from_secs(1);
let reader = op.reader_with(&path).if_unmodified_since(since).await?;
let res = reader.read(..).await;
assert!(res.is_err());
@@ -325,7 +325,7 @@ pub async fn test_reader_with_if_unmodified_since(op:
Operator) -> anyhow::Resul
sleep(Duration::from_secs(1)).await;
- let since = last_modified_time + chrono::Duration::seconds(1);
+ let since = last_modified_time + Duration::from_secs(1);
let reader = op.reader_with(&path).if_unmodified_since(since).await?;
let bs = reader.read(..).await?.to_bytes();
assert_eq!(bs, content);
@@ -565,7 +565,7 @@ pub async fn test_read_with_if_modified_since(op: Operator)
-> anyhow::Result<()
.expect("write must succeed");
let last_modified_time = op.stat(&path).await?.last_modified().unwrap();
- let since = last_modified_time - chrono::Duration::seconds(1);
+ let since = last_modified_time - Duration::from_secs(1);
let bs = op
.read_with(&path)
.if_modified_since(since)
@@ -575,7 +575,7 @@ pub async fn test_read_with_if_modified_since(op: Operator)
-> anyhow::Result<()
sleep(Duration::from_secs(1)).await;
- let since = last_modified_time + chrono::Duration::seconds(1);
+ let since = last_modified_time + Duration::from_secs(1);
let res = op.read_with(&path).if_modified_since(since).await;
assert!(res.is_err());
assert_eq!(res.unwrap_err().kind(), ErrorKind::ConditionNotMatch);
@@ -596,14 +596,14 @@ pub async fn test_read_with_if_unmodified_since(op:
Operator) -> anyhow::Result<
.expect("write must succeed");
let last_modified = op.stat(&path).await?.last_modified().unwrap();
- let since = last_modified - chrono::Duration::seconds(3600);
+ let since = last_modified - Duration::from_secs(3600);
let res = op.read_with(&path).if_unmodified_since(since).await;
assert!(res.is_err());
assert_eq!(res.unwrap_err().kind(), ErrorKind::ConditionNotMatch);
sleep(Duration::from_secs(1)).await;
- let since = last_modified + chrono::Duration::seconds(1);
+ let since = last_modified + Duration::from_secs(1);
let bs = op
.read_with(&path)
.if_unmodified_since(since)
diff --git a/integrations/cloud_filter/src/lib.rs
b/integrations/cloud_filter/src/lib.rs
index dde66ac3f..6e635f0cb 100644
--- a/integrations/cloud_filter/src/lib.rs
+++ b/integrations/cloud_filter/src/lib.rs
@@ -231,7 +231,7 @@ impl Filter for CloudFilter {
.size(metadata.content_length())
.written(
FileTime::from_unix_time(
-
metadata.last_modified().unwrap_or_default().timestamp(),
+
metadata.last_modified().unwrap_or_default().as_second(),
)
.expect("valid time"),
)
diff --git a/integrations/object_store/Cargo.toml
b/integrations/object_store/Cargo.toml
index 236d5417a..d1f91f6c5 100644
--- a/integrations/object_store/Cargo.toml
+++ b/integrations/object_store/Cargo.toml
@@ -39,7 +39,9 @@ path = "tests/behavior/main.rs"
[dependencies]
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 9671bedd7..983612882 100644
--- a/integrations/object_store/src/lib.rs
+++ b/integrations/object_store/src/lib.rs
@@ -97,3 +97,11 @@ mod assert_send {
assert_send(store.list_with_delimiter(None));
}
}
+
+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 datetime_to_timestamp(dt: chrono::DateTime<chrono::Utc>) ->
Option<jiff::Timestamp> {
+ jiff::Timestamp::new(dt.timestamp(), dt.timestamp_subsec_nanos() as
i32).ok()
+}
diff --git a/integrations/object_store/src/service/core.rs
b/integrations/object_store/src/service/core.rs
index bfcf61d66..6c7f9443d 100644
--- a/integrations/object_store/src/service/core.rs
+++ b/integrations/object_store/src/service/core.rs
@@ -15,13 +15,13 @@
// specific language governing permissions and limitations
// under the License.
-use std::borrow::Cow;
-
+use crate::{datetime_to_timestamp, timestamp_to_datetime};
use object_store::{
Attribute, AttributeValue, GetOptions, GetRange, ObjectMeta, PutOptions,
PutResult,
};
use opendal::raw::*;
use opendal::*;
+use std::borrow::Cow;
/// Parse OpStat arguments to object_store GetOptions for head requests
pub fn parse_op_stat(args: &OpStat) -> Result<GetOptions> {
@@ -43,11 +43,11 @@ pub fn parse_op_stat(args: &OpStat) -> Result<GetOptions> {
}
if let Some(if_modified_since) = args.if_modified_since() {
- options.if_modified_since = Some(if_modified_since);
+ options.if_modified_since = timestamp_to_datetime(if_modified_since);
}
if let Some(if_unmodified_since) = args.if_unmodified_since() {
- options.if_unmodified_since = Some(if_unmodified_since);
+ options.if_unmodified_since =
timestamp_to_datetime(if_unmodified_since);
}
Ok(options)
@@ -70,11 +70,11 @@ pub fn parse_op_read(args: &OpRead) -> Result<GetOptions> {
}
if let Some(if_modified_since) = args.if_modified_since() {
- options.if_modified_since = Some(if_modified_since);
+ options.if_modified_since = timestamp_to_datetime(if_modified_since);
}
if let Some(if_unmodified_since) = args.if_unmodified_since() {
- options.if_unmodified_since = Some(if_unmodified_since);
+ options.if_unmodified_since =
timestamp_to_datetime(if_unmodified_since);
}
if !args.range().is_full() {
@@ -152,7 +152,9 @@ pub fn format_put_result(result: PutResult) -> Metadata {
pub fn format_metadata(meta: &ObjectMeta) -> Metadata {
let mut metadata = Metadata::new(EntryMode::FILE);
metadata.set_content_length(meta.size);
- metadata.set_last_modified(meta.last_modified);
+ if let Some(last_modified) = datetime_to_timestamp(meta.last_modified) {
+ metadata.set_last_modified(last_modified);
+ }
if let Some(etag) = &meta.e_tag {
metadata.set_etag(etag);
}
diff --git a/integrations/object_store/src/store.rs
b/integrations/object_store/src/store.rs
index ec1374bc0..177ce72d5 100644
--- a/integrations/object_store/src/store.rs
+++ b/integrations/object_store/src/store.rs
@@ -21,6 +21,7 @@ use std::io;
use std::sync::Arc;
use crate::utils::*;
+use crate::{datetime_to_timestamp, timestamp_to_datetime};
use async_trait::async_trait;
use futures::FutureExt;
use futures::StreamExt;
@@ -317,10 +318,14 @@ impl ObjectStore for OpendalStore {
if let Some(if_none_match) = &options.if_none_match {
s = s.if_none_match(if_none_match.as_str());
}
- if let Some(if_modified_since) = options.if_modified_since {
+ if let Some(if_modified_since) =
+ options.if_modified_since.and_then(datetime_to_timestamp)
+ {
s = s.if_modified_since(if_modified_since);
}
- if let Some(if_unmodified_since) = options.if_unmodified_since {
+ if let Some(if_unmodified_since) =
+ options.if_unmodified_since.and_then(datetime_to_timestamp)
+ {
s = s.if_unmodified_since(if_unmodified_since);
}
s.into_send()
@@ -341,7 +346,10 @@ impl ObjectStore for OpendalStore {
let meta = ObjectMeta {
location: location.clone(),
- last_modified: meta.last_modified().unwrap_or_default(),
+ last_modified: meta
+ .last_modified()
+ .and_then(timestamp_to_datetime)
+ .unwrap_or_default(),
size: meta.content_length(),
e_tag: meta.etag().map(|x| x.to_string()),
version: meta.version().map(|x| x.to_string()),
@@ -367,10 +375,14 @@ impl ObjectStore for OpendalStore {
if let Some(if_none_match) = options.if_none_match {
r = r.if_none_match(if_none_match.as_str());
}
- if let Some(if_modified_since) = options.if_modified_since {
+ if let Some(if_modified_since) =
+ options.if_modified_since.and_then(datetime_to_timestamp)
+ {
r = r.if_modified_since(if_modified_since);
}
- if let Some(if_unmodified_since) = options.if_unmodified_since {
+ if let Some(if_unmodified_since) =
+ options.if_unmodified_since.and_then(datetime_to_timestamp)
+ {
r = r.if_unmodified_since(if_unmodified_since);
}
r.into_send()
diff --git a/integrations/object_store/src/utils.rs
b/integrations/object_store/src/utils.rs
index 34a511227..efce4d601 100644
--- a/integrations/object_store/src/utils.rs
+++ b/integrations/object_store/src/utils.rs
@@ -20,6 +20,7 @@ use object_store::ObjectMeta;
use opendal::Metadata;
use std::future::IntoFuture;
+use crate::timestamp_to_datetime;
/// Conditionally add the `Send` marker trait for the wrapped type.
/// Only take effect when the `send_wrapper` feature is enabled.
#[cfg(not(feature = "send_wrapper"))]
@@ -57,7 +58,10 @@ pub fn format_object_store_error(err: opendal::Error, path:
&str) -> object_stor
pub fn format_object_meta(path: &str, meta: &Metadata) -> ObjectMeta {
ObjectMeta {
location: path.into(),
- last_modified: meta.last_modified().unwrap_or_default(),
+ last_modified: meta
+ .last_modified()
+ .and_then(timestamp_to_datetime)
+ .unwrap_or_default(),
size: meta.content_length(),
e_tag: meta.etag().map(|x| x.to_string()),
version: meta.version().map(|x| x.to_string()),