You've already forked parse_datetime
mirror of
https://github.com/uutils/parse_datetime.git
synced 2026-06-10 16:13:15 -07:00
Compare commits
173 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ea52a79163 | |||
| 938aa9694b | |||
| 51e294724c | |||
| fa53ec79bd | |||
| 90d22a2c37 | |||
| 06aac3f56f | |||
| 240abf791e | |||
| 34f226fd98 | |||
| 00dc90dd10 | |||
| 3c67f4b5c9 | |||
| faf363c2e6 | |||
| 56410cebcf | |||
| d777be1bb6 | |||
| 6429ef26c5 | |||
| fa311c0dd4 | |||
| 7ab9a02761 | |||
| 78877a1b98 | |||
| 623c626b3a | |||
| a9bccfa20a | |||
| dba1374f8e | |||
| 9b266bcb17 | |||
| 5e3fc539a3 | |||
| c26d83fd6e | |||
| a841ad0fc4 | |||
| 8ca89bdb55 | |||
| 48852068de | |||
| 3813a3bae9 | |||
| 313de7ba7c | |||
| 7913ecd888 | |||
| 8a528468ae | |||
| 212c6f7c24 | |||
| cd7020f038 | |||
| e543ee64a7 | |||
| 19d49cfe73 | |||
| 86d72fc867 | |||
| bbcafc42f9 | |||
| 1570d92fc5 | |||
| e41e26fef1 | |||
| d5015a641e | |||
| 5e6bddb6f5 | |||
| ced645a4f4 | |||
| d75338a51b | |||
| d4f67bbde0 | |||
| ba19b94acd | |||
| f7f789913a | |||
| 7e84a62b9e | |||
| db8c1d364f | |||
| e1aa18d263 | |||
| a05bd1d06e | |||
| a75107c69d | |||
| 0f5b6bf16e | |||
| 1bb93d7fe9 | |||
| 138999131b | |||
| fc14854394 | |||
| be45c2734d | |||
| acf9b9c76e | |||
| 04494f6ddb | |||
| 20a39748f0 | |||
| 113100e669 | |||
| ff2113eabe | |||
| ad9a056826 | |||
| d1263e0e7e | |||
| 5b81981a8a | |||
| 85957480b3 | |||
| 0d04eeb08d | |||
| 0dddb4b726 | |||
| deffff9803 | |||
| 96d8c7c294 | |||
| 249c079790 | |||
| 261b28db22 | |||
| cdc1b64fcf | |||
| 9e27be1e1a | |||
| 9bb047eeab | |||
| 040561c235 | |||
| 9009bfc4ed | |||
| c39e01748c | |||
| 325ae3a408 | |||
| 1ded0a062c | |||
| 0047868a35 | |||
| 5d11c142b5 | |||
| 8ef448acb5 | |||
| 0ad9ef3e6b | |||
| 4dfa20c7b0 | |||
| e8ab1a46e2 | |||
| 57d3527d81 | |||
| 48255280aa | |||
| bddcc6067f | |||
| be7fe1dc12 | |||
| 70fde9fa18 | |||
| 2d05b14a2d | |||
| 96db1a281e | |||
| 93c02dc0b7 | |||
| 29d641389d | |||
| adb5fabfa7 | |||
| 02e5c22985 | |||
| c6feb9a251 | |||
| 852638fef0 | |||
| 5c34517469 | |||
| 47c5f3620b | |||
| 1e43cc945f | |||
| f9ce5047a5 | |||
| 4c3fd2b1ed | |||
| 9a7f87ac09 | |||
| 0b0aa70193 | |||
| 0c44becec8 | |||
| 64dfea4b47 | |||
| 0bdabd5303 | |||
| 2112830d8b | |||
| 2737b4a0f2 | |||
| f10749eade | |||
| a7380508bc | |||
| 7f0a909752 | |||
| ff0f99bea5 | |||
| dc0d8a3aa0 | |||
| b615effc4e | |||
| cebf55cf82 | |||
| efee20bf01 | |||
| c084001056 | |||
| a35530ed4a | |||
| 6cfcc985a8 | |||
| 497bebb9e7 | |||
| dfd43a6d65 | |||
| 51dd843ded | |||
| c24d593821 | |||
| bed2d16e67 | |||
| 7ab1ad2f0e | |||
| c1a2bef4a6 | |||
| 673d5b600e | |||
| 83e1431db0 | |||
| 80f8fdf883 | |||
| 22bdd8f49c | |||
| dc508c469b | |||
| e503de7559 | |||
| 7ee33d1fb1 | |||
| bc33770075 | |||
| 70d3e53604 | |||
| 1ba787d1c3 | |||
| 33cefd7db2 | |||
| d0d913e161 | |||
| c784a721ee | |||
| 29e7a5c335 | |||
| 8d797fcbcb | |||
| c177117428 | |||
| 03c8e81a10 | |||
| 7547f31b76 | |||
| 1c32733f38 | |||
| 5278394b7c | |||
| e53aabd914 | |||
| e5d7fbcece | |||
| 060998e90e | |||
| a272f55948 | |||
| 9c5da7959c | |||
| a60f1d89f5 | |||
| 1d78cc5a3f | |||
| 6ba55a075b | |||
| b439960eb1 | |||
| f1a15ab2b3 | |||
| 0bd4dd716a | |||
| 674909c0f9 | |||
| 57bcf7f433 | |||
| 2e80358014 | |||
| 15fb185d95 | |||
| e64c163f47 | |||
| 86378bc326 | |||
| 6a52551dea | |||
| 21e7e01fc8 | |||
| 1359dc9349 | |||
| daec32d5c4 | |||
| 7a3d0bafca | |||
| 537df73bdd | |||
| 3e4c6e3b6c | |||
| 29e64c3cda | |||
| db00d0686f |
+41
-56
@@ -13,15 +13,9 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: check
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cargo check
|
||||
|
||||
test:
|
||||
name: cargo test
|
||||
@@ -30,31 +24,18 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: cargo test
|
||||
|
||||
fmt:
|
||||
name: cargo fmt --all -- --check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: rustup component add rustfmt
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
- run: cargo fmt --all -- --check
|
||||
|
||||
clippy:
|
||||
name: cargo clippy -- -D warnings
|
||||
@@ -63,17 +44,10 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macOS-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: stable
|
||||
override: true
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- run: rustup component add clippy
|
||||
- uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: -- -D warnings
|
||||
- run: cargo clippy --all-targets -- -D warnings
|
||||
|
||||
coverage:
|
||||
name: Code Coverage
|
||||
@@ -86,7 +60,7 @@ jobs:
|
||||
- { os: macos-latest , features: macos }
|
||||
- { os: windows-latest , features: windows }
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
@@ -101,28 +75,22 @@ jobs:
|
||||
if [ -n "${{ matrix.job.toolchain }}" ]; then TOOLCHAIN="${{ matrix.job.toolchain }}" ; fi
|
||||
outputs TOOLCHAIN
|
||||
# target-specific options
|
||||
# * CARGO_FEATURES_OPTION
|
||||
CARGO_FEATURES_OPTION='--all -- --check' ; ## default to '--all-features' for code coverage
|
||||
# * CODECOV_FLAGS
|
||||
CODECOV_FLAGS=$( echo "${{ matrix.job.os }}" | sed 's/[^[:alnum:]]/_/g' )
|
||||
outputs CODECOV_FLAGS
|
||||
|
||||
- name: rust toolchain ~ install
|
||||
uses: actions-rs/toolchain@v1
|
||||
uses: dtolnay/rust-toolchain@nightly
|
||||
with:
|
||||
toolchain: ${{ steps.vars.outputs.TOOLCHAIN }}
|
||||
default: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
components: llvm-tools-preview
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --no-fail-fast
|
||||
run: cargo test --no-fail-fast
|
||||
env:
|
||||
CARGO_INCREMENTAL: "0"
|
||||
RUSTC_WRAPPER: ""
|
||||
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
|
||||
RUSTFLAGS: "-Cinstrument-coverage -Zcoverage-options=branch -Ccodegen-units=1 -Copt-level=0 -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
|
||||
RUSTDOCFLAGS: "-Cpanic=abort"
|
||||
LLVM_PROFILE_FILE: "parse_datetime-%p-%m.profraw"
|
||||
- name: "`grcov` ~ install"
|
||||
id: build_grcov
|
||||
shell: bash
|
||||
@@ -150,17 +118,34 @@ jobs:
|
||||
COVERAGE_REPORT_FILE="${COVERAGE_REPORT_DIR}/lcov.info"
|
||||
mkdir -p "${COVERAGE_REPORT_DIR}"
|
||||
# display coverage files
|
||||
grcov . --output-type files --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()" | sort --unique
|
||||
grcov . --binary-path="${COVERAGE_REPORT_DIR}" --output-type files --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()" | sort --unique
|
||||
# generate coverage report
|
||||
grcov . --output-type lcov --output-path "${COVERAGE_REPORT_FILE}" --branch --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()"
|
||||
grcov . --binary-path="${COVERAGE_REPORT_DIR}" --output-type lcov --output-path "${COVERAGE_REPORT_FILE}" --branch --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()"
|
||||
echo "report=${COVERAGE_REPORT_FILE}" >> $GITHUB_OUTPUT
|
||||
- name: Upload coverage results (to Codecov.io)
|
||||
uses: codecov/codecov-action@v3
|
||||
# if: steps.vars.outputs.HAS_CODECOV_TOKEN
|
||||
uses: codecov/codecov-action@v5
|
||||
with:
|
||||
# token: ${{ secrets.CODECOV_TOKEN }}
|
||||
file: ${{ steps.coverage.outputs.report }}
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: ${{ steps.coverage.outputs.report }}
|
||||
## flags: IntegrationTests, UnitTests, ${{ steps.vars.outputs.CODECOV_FLAGS }}
|
||||
flags: ${{ steps.vars.outputs.CODECOV_FLAGS }}
|
||||
name: codecov-umbrella
|
||||
fail_ci_if_error: false
|
||||
|
||||
fuzz:
|
||||
name: Run the fuzzers
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RUN_FOR: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
- name: Install `cargo-fuzz`
|
||||
run: cargo install cargo-fuzz
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Run from_str for XX seconds
|
||||
shell: bash
|
||||
run: |
|
||||
## Run it
|
||||
cd fuzz
|
||||
cargo +nightly fuzz run fuzz_parse_datetime -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
target/
|
||||
Generated
+312
-26
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
@@ -12,24 +12,187 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime_to_duration"
|
||||
version = "0.1.3"
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"time",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"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 = "js-sys"
|
||||
version = "0.3.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "parse_datetime"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"nom",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.1"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -38,28 +201,151 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.1"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.160"
|
||||
name = "syn"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
||||
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"time-core",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.0"
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
+7
-6
@@ -1,12 +1,13 @@
|
||||
[package]
|
||||
name = "humantime_to_duration"
|
||||
description = " parsing human-readable relative time strings and converting them to a Duration"
|
||||
version = "0.1.3"
|
||||
name = "parse_datetime"
|
||||
description = "parsing human-readable time strings and converting them to a DateTime"
|
||||
version = "0.7.0"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/uutils/humantime_to_duration"
|
||||
repository = "https://github.com/uutils/parse_datetime"
|
||||
readme = "README.md"
|
||||
|
||||
[dependencies]
|
||||
regex = "1.7"
|
||||
time = "0.3.20"
|
||||
regex = "1.10.4"
|
||||
chrono = { version="0.4.38", default-features=false, features=["std", "alloc", "clock"] }
|
||||
nom = "7.1.3"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 uutils
|
||||
Copyright (c) 2023 Sylvestre Ledru and others
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
# humantime_to_duration
|
||||
# parse_datetime
|
||||
|
||||
[](https://crates.io/crates/humantime_to_duration)
|
||||
[](https://github.com/uutils/humantime_to_duration/blob/main/LICENSE)
|
||||
[](https://codecov.io/gh/uutils/humantime_to_duration)
|
||||
[](https://crates.io/crates/parse_datetime)
|
||||
[](https://github.com/uutils/parse_datetime/blob/main/LICENSE)
|
||||
[](https://codecov.io/gh/uutils/parse_datetime)
|
||||
|
||||
A Rust crate for parsing human-readable relative time strings and converting them to a `Duration`.
|
||||
A Rust crate for parsing human-readable relative time strings and human-readable datetime strings and converting them to a `DateTime`.
|
||||
|
||||
## Features
|
||||
|
||||
- Parses a variety of human-readable time formats.
|
||||
- Parses a variety of human-readable and standard time formats.
|
||||
- Supports positive and negative durations.
|
||||
- Allows for chaining time units (e.g., "1 hour 2 minutes" or "2 days and 2 hours").
|
||||
- Calculate durations relative to a specified date.
|
||||
- Relies on Chrono
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -18,21 +20,37 @@ Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
humantime_to_duration = "0.1.1"
|
||||
parse_datetime = "0.6.0"
|
||||
```
|
||||
|
||||
Then, import the crate and use the from_str function:
|
||||
```
|
||||
use humantime_to_duration::from_str;
|
||||
use time::Duration;
|
||||
Then, import the crate and use the `parse_datetime_at_date` function:
|
||||
|
||||
let duration = from_str("+3 days");
|
||||
assert_eq!(duration.unwrap(), Duration::days(3));
|
||||
```rs
|
||||
use chrono::{Duration, Local};
|
||||
use parse_datetime::parse_datetime_at_date;
|
||||
|
||||
let now = Local::now();
|
||||
let after = parse_datetime_at_date(now, "+3 days");
|
||||
|
||||
assert_eq!(
|
||||
(now + Duration::days(3)).naive_utc(),
|
||||
after.unwrap().naive_utc()
|
||||
);
|
||||
```
|
||||
|
||||
For DateTime parsing, import the `parse_datetime` function:
|
||||
|
||||
```rs
|
||||
use parse_datetime::parse_datetime;
|
||||
use chrono::{Local, TimeZone};
|
||||
|
||||
let dt = parse_datetime("2021-02-14 06:37:47");
|
||||
assert_eq!(dt.unwrap(), Local.with_ymd_and_hms(2021, 2, 14, 6, 37, 47).unwrap());
|
||||
```
|
||||
|
||||
### Supported Formats
|
||||
|
||||
The `from_str` function supports the following formats for relative time:
|
||||
The `parse_datetime` and `parse_datetime_at_date` functions support absolute datetime and the following relative times:
|
||||
|
||||
- `num` `unit` (e.g., "-1 hour", "+3 days")
|
||||
- `unit` (e.g., "hour", "day")
|
||||
@@ -40,28 +58,37 @@ The `from_str` function supports the following formats for relative time:
|
||||
- "yesterday"
|
||||
- "tomorrow"
|
||||
- use "ago" for the past
|
||||
- use "next" or "last" with `unit` (e.g., "next week", "last year")
|
||||
- combined units with "and" or "," (e.g., "2 years and 1 month", "1 day, 2 hours" or "2 weeks 1 second")
|
||||
- unix timestamps (for example "@0" "@1344000")
|
||||
|
||||
`num` can be a positive or negative integer.
|
||||
`unit` can be one of the following: "fortnight", "week", "day", "hour", "minute", "min", "second", "sec" and their plural forms.
|
||||
|
||||
## Return Values
|
||||
|
||||
The `from_str` function returns:
|
||||
### parse_datetime and parse_datetime_at_date
|
||||
|
||||
- `Ok(Duration)` - If the input string can be parsed as a relative time
|
||||
- `Err(ParseDurationError)` - If the input string cannot be parsed as a relative time
|
||||
The `parse_datetime` and `parse_datetime_at_date` function return:
|
||||
|
||||
This function will return `Err(ParseDurationError::InvalidInput)` if the input string
|
||||
cannot be parsed as a relative time.
|
||||
- `Ok(DateTime<FixedOffset>)` - If the input string can be parsed as a datetime
|
||||
- `Err(ParseDateTimeError::InvalidInput)` - If the input string cannot be parsed
|
||||
|
||||
## Fuzzer
|
||||
|
||||
To run the fuzzer:
|
||||
|
||||
```
|
||||
$ cargo fuzz run fuzz_from_str
|
||||
$ cd fuzz
|
||||
$ cargo install cargo-fuzz
|
||||
$ cargo +nightly fuzz run fuzz_parse_datetime
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the [MIT License](LICENSE).
|
||||
|
||||
## Note
|
||||
|
||||
At some point, this crate was called humantime_to_duration.
|
||||
It has been renamed to cover more cases.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
corpus
|
||||
Generated
+294
-33
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
@@ -11,12 +11,39 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[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 = "arbitrary"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
@@ -33,14 +60,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "fuzz_from_str"
|
||||
version = "0.1.0"
|
||||
name = "chrono"
|
||||
version = "0.4.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
|
||||
dependencies = [
|
||||
"humantime_to_duration",
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "fuzz_parse_datetime"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"libfuzzer-sys",
|
||||
"parse_datetime",
|
||||
"rand",
|
||||
"regex",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -55,11 +100,26 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime_to_duration"
|
||||
version = "0.1.0"
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"time",
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"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]]
|
||||
@@ -71,6 +131,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.142"
|
||||
@@ -79,20 +148,50 @@ checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.4.6"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "beb09950ae85a0a94b27676cccf37da5ff13f27076aa1adbc6545dd0d0e1bd4e"
|
||||
checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"cc",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
name = "log"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
@@ -100,12 +199,39 @@ version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "parse_datetime"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"nom",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
@@ -138,9 +264,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.1"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -149,34 +287,157 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.1"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.160"
|
||||
name = "syn"
|
||||
version = "2.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
||||
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"time-core",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.0"
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
+10
-10
@@ -1,22 +1,22 @@
|
||||
[package]
|
||||
name = "fuzz_from_str"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
name = "fuzz_parse_datetime"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.4"
|
||||
libfuzzer-sys = "0.4"
|
||||
regex = "1.8.1"
|
||||
time = "0.3.20"
|
||||
rand = "0.8.5"
|
||||
libfuzzer-sys = "0.4.7"
|
||||
regex = "1.10.4"
|
||||
chrono = { version="0.4", default-features=false, features=["std", "alloc", "clock"] }
|
||||
|
||||
[dependencies.humantime_to_duration]
|
||||
[dependencies.parse_datetime]
|
||||
path = "../"
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_from_str"
|
||||
path = "fuzz_targets/from_str.rs"
|
||||
name = "fuzz_parse_datetime"
|
||||
path = "fuzz_targets/parse_datetime.rs"
|
||||
test = false
|
||||
doc = false
|
||||
|
||||
@@ -4,5 +4,5 @@ use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let s = std::str::from_utf8(data).unwrap_or("");
|
||||
let _ = humantime_to_duration::from_str(s);
|
||||
let _ = parse_datetime::parse_datetime(s);
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended"
|
||||
]
|
||||
}
|
||||
+494
-240
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,210 @@
|
||||
use chrono::{DateTime, FixedOffset, Local, NaiveTime, TimeZone};
|
||||
use regex::Regex;
|
||||
|
||||
mod time_only_formats {
|
||||
pub const HH_MM: &str = "%R";
|
||||
pub const HH_MM_SS: &str = "%T";
|
||||
pub const TWELVEHOUR: &str = "%r";
|
||||
}
|
||||
|
||||
/// Convert a military time zone string to a time zone offset.
|
||||
///
|
||||
/// Military time zones are the letters A through Z except J. They are
|
||||
/// described in RFC 5322.
|
||||
fn to_offset(tz: &str) -> Option<FixedOffset> {
|
||||
let hour = match tz {
|
||||
"A" => 1,
|
||||
"B" => 2,
|
||||
"C" => 3,
|
||||
"D" => 4,
|
||||
"E" => 5,
|
||||
"F" => 6,
|
||||
"G" => 7,
|
||||
"H" => 8,
|
||||
"I" => 9,
|
||||
"K" => 10,
|
||||
"L" => 11,
|
||||
"M" => 12,
|
||||
"N" => -1,
|
||||
"O" => -2,
|
||||
"P" => -3,
|
||||
"Q" => -4,
|
||||
"R" => -5,
|
||||
"S" => -6,
|
||||
"T" => -7,
|
||||
"U" => -8,
|
||||
"V" => -9,
|
||||
"W" => -10,
|
||||
"X" => -11,
|
||||
"Y" => -12,
|
||||
"Z" => 0,
|
||||
_ => return None,
|
||||
};
|
||||
let offset_in_sec = hour * 3600;
|
||||
FixedOffset::east_opt(offset_in_sec)
|
||||
}
|
||||
|
||||
/// Parse a time string without an offset and apply an offset to it.
|
||||
///
|
||||
/// Multiple formats are attempted when parsing the string.
|
||||
fn parse_time_with_offset_multi(
|
||||
date: DateTime<Local>,
|
||||
offset: FixedOffset,
|
||||
s: &str,
|
||||
) -> Option<DateTime<FixedOffset>> {
|
||||
for fmt in [
|
||||
time_only_formats::HH_MM,
|
||||
time_only_formats::HH_MM_SS,
|
||||
time_only_formats::TWELVEHOUR,
|
||||
] {
|
||||
let parsed = match NaiveTime::parse_from_str(s, fmt) {
|
||||
Ok(t) => t,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let parsed_dt = date.date_naive().and_time(parsed);
|
||||
match offset.from_local_datetime(&parsed_dt).single() {
|
||||
Some(dt) => return Some(dt),
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn parse_time_only(date: DateTime<Local>, s: &str) -> Option<DateTime<FixedOffset>> {
|
||||
let re =
|
||||
Regex::new(r"^(?<time>.*?)(?:(?<sign>\+|-)(?<h>[0-9]{1,2}):?(?<m>[0-9]{0,2}))?$").unwrap();
|
||||
let captures = re.captures(s)?;
|
||||
|
||||
// Parse the sign, hour, and minute to get a `FixedOffset`, if possible.
|
||||
let parsed_offset = match captures.name("h") {
|
||||
Some(hours) if !(hours.as_str().is_empty()) => {
|
||||
let mut offset_in_sec = hours.as_str().parse::<i32>().unwrap() * 3600;
|
||||
match captures.name("m") {
|
||||
Some(minutes) if !(minutes.as_str().is_empty()) => {
|
||||
offset_in_sec += minutes.as_str().parse::<i32>().unwrap() * 60;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
offset_in_sec *= if &captures["sign"] == "-" { -1 } else { 1 };
|
||||
FixedOffset::east_opt(offset_in_sec)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Parse the time and apply the parsed offset.
|
||||
let s = captures["time"].trim();
|
||||
let offset = match parsed_offset {
|
||||
Some(offset) => offset,
|
||||
None => *date.offset(),
|
||||
};
|
||||
if let Some(result) = parse_time_with_offset_multi(date, offset, s) {
|
||||
return Some(result);
|
||||
}
|
||||
|
||||
// Military time zones are specified in RFC 5322, Section 4.3
|
||||
// "Obsolete Date and Time".
|
||||
// <https://datatracker.ietf.org/doc/html/rfc5322>
|
||||
//
|
||||
// We let the parsing above handle "5:00 AM" so at this point we
|
||||
// should be guaranteed that we don't have an AM/PM suffix. That
|
||||
// way, we can safely parse "5:00M" here without interference.
|
||||
let re = Regex::new(r"(?<time>.*?)(?<tz>[A-IKLMN-YZ])").unwrap();
|
||||
let captures = re.captures(s)?;
|
||||
if let Some(tz) = captures.name("tz") {
|
||||
let s = captures["time"].trim();
|
||||
let offset = match to_offset(tz.as_str()) {
|
||||
Some(offset) => offset,
|
||||
None => *date.offset(),
|
||||
};
|
||||
if let Some(result) = parse_time_with_offset_multi(date, offset, s) {
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::parse_time_only_str::parse_time_only;
|
||||
use chrono::{DateTime, Local, TimeZone};
|
||||
use std::env;
|
||||
|
||||
fn get_test_date() -> DateTime<Local> {
|
||||
Local.with_ymd_and_hms(2024, 3, 3, 0, 0, 0).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_time_only() {
|
||||
env::set_var("TZ", "UTC");
|
||||
let parsed_time = parse_time_only(get_test_date(), "21:04")
|
||||
.unwrap()
|
||||
.timestamp();
|
||||
assert_eq!(parsed_time, 1709499840)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_military_time_zones() {
|
||||
env::set_var("TZ", "UTC");
|
||||
let date = get_test_date();
|
||||
let actual = parse_time_only(date, "05:00C").unwrap().timestamp();
|
||||
// Computed via `date -u -d "2024-03-03 05:00:00C" +%s`, using a
|
||||
// version of GNU date after v8.32 (earlier versions had a bug).
|
||||
let expected = 1709431200;
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_time_with_offset() {
|
||||
env::set_var("TZ", "UTC");
|
||||
let parsed_time = parse_time_only(get_test_date(), "21:04 +0530")
|
||||
.unwrap()
|
||||
.timestamp();
|
||||
assert_eq!(parsed_time, 1709480040);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_time_with_hour_only_offset() {
|
||||
env::set_var("TZ", "UTC");
|
||||
let parsed_time = parse_time_only(get_test_date(), "22:04 +01")
|
||||
.unwrap()
|
||||
.timestamp();
|
||||
assert_eq!(parsed_time, 1709499840);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_time_with_hour_only_neg_offset() {
|
||||
env::set_var("TZ", "UTC");
|
||||
let parsed_time = parse_time_only(get_test_date(), "17:04 -04")
|
||||
.unwrap()
|
||||
.timestamp();
|
||||
assert_eq!(parsed_time, 1709499840);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_time_with_seconds() {
|
||||
env::set_var("TZ", "UTC");
|
||||
let parsed_time = parse_time_only(get_test_date(), "21:04:30")
|
||||
.unwrap()
|
||||
.timestamp();
|
||||
assert_eq!(parsed_time, 1709499870)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_time_with_seconds_with_offset() {
|
||||
env::set_var("TZ", "UTC");
|
||||
let parsed_time = parse_time_only(get_test_date(), "21:04:30 +0530")
|
||||
.unwrap()
|
||||
.timestamp();
|
||||
assert_eq!(parsed_time, 1709480070)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_twelve_hour_time() {
|
||||
env::set_var("TZ", "UTC");
|
||||
let parsed_time = parse_time_only(get_test_date(), "9:04:00 PM")
|
||||
.unwrap()
|
||||
.timestamp();
|
||||
assert_eq!(parsed_time, 1709499840)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
use core::fmt;
|
||||
use std::error::Error;
|
||||
use std::fmt::Display;
|
||||
use std::num::ParseIntError;
|
||||
|
||||
use nom::branch::alt;
|
||||
use nom::character::complete::{char, digit1};
|
||||
use nom::combinator::all_consuming;
|
||||
use nom::multi::fold_many0;
|
||||
use nom::sequence::preceded;
|
||||
use nom::sequence::tuple;
|
||||
use nom::{self, IResult};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ParseTimestampError {
|
||||
InvalidNumber(ParseIntError),
|
||||
InvalidInput,
|
||||
}
|
||||
|
||||
impl Display for ParseTimestampError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::InvalidInput => {
|
||||
write!(f, "Invalid input string: cannot be parsed as a timestamp")
|
||||
}
|
||||
Self::InvalidNumber(err) => {
|
||||
write!(f, "Invalid timestamp number: {err}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for ParseTimestampError {}
|
||||
|
||||
// TODO is this necessary
|
||||
impl From<ParseIntError> for ParseTimestampError {
|
||||
fn from(err: ParseIntError) -> Self {
|
||||
Self::InvalidNumber(err)
|
||||
}
|
||||
}
|
||||
|
||||
type NomError<'a> = nom::Err<nom::error::Error<&'a str>>;
|
||||
|
||||
impl<'a> From<NomError<'a>> for ParseTimestampError {
|
||||
fn from(_err: NomError<'a>) -> Self {
|
||||
Self::InvalidInput
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn parse_timestamp(s: &str) -> Result<i64, ParseTimestampError> {
|
||||
let s = s.trim().to_lowercase();
|
||||
let s = s.as_str();
|
||||
|
||||
let res: IResult<&str, (char, &str)> = all_consuming(preceded(
|
||||
char('@'),
|
||||
tuple((
|
||||
// Note: to stay compatible with gnu date this code allows
|
||||
// multiple + and - and only considers the last one
|
||||
fold_many0(
|
||||
// parse either + or -
|
||||
alt((char('+'), char('-'))),
|
||||
// start with a +
|
||||
|| '+',
|
||||
// whatever we get (+ or -), update the accumulator to that value
|
||||
|_, c| c,
|
||||
),
|
||||
digit1,
|
||||
)),
|
||||
))(s);
|
||||
|
||||
let (_, (sign, number_str)) = res?;
|
||||
|
||||
let mut number = number_str.parse::<i64>()?;
|
||||
|
||||
if sign == '-' {
|
||||
number *= -1;
|
||||
}
|
||||
|
||||
Ok(number)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::parse_timestamp::parse_timestamp;
|
||||
|
||||
#[test]
|
||||
fn test_valid_timestamp() {
|
||||
assert_eq!(parse_timestamp("@1234"), Ok(1234));
|
||||
assert_eq!(parse_timestamp("@99999"), Ok(99999));
|
||||
assert_eq!(parse_timestamp("@-4"), Ok(-4));
|
||||
assert_eq!(parse_timestamp("@-99999"), Ok(-99999));
|
||||
assert_eq!(parse_timestamp("@+4"), Ok(4));
|
||||
assert_eq!(parse_timestamp("@0"), Ok(0));
|
||||
|
||||
// gnu date accepts numbers signs and uses the last sign
|
||||
assert_eq!(parse_timestamp("@---+12"), Ok(12));
|
||||
assert_eq!(parse_timestamp("@+++-12"), Ok(-12));
|
||||
assert_eq!(parse_timestamp("@+----+12"), Ok(12));
|
||||
assert_eq!(parse_timestamp("@++++-123"), Ok(-123));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_timestamp() {
|
||||
assert!(parse_timestamp("@").is_err());
|
||||
assert!(parse_timestamp("@+--+").is_err());
|
||||
assert!(parse_timestamp("@+1ab2").is_err());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
use chrono::Weekday;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::combinator::value;
|
||||
use nom::{self, IResult};
|
||||
|
||||
// Helper macro to simplify tag matching
|
||||
macro_rules! tag_match {
|
||||
($day:expr, $($pattern:expr),+) => {
|
||||
value($day, alt(($(tag($pattern)),+)))
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn parse_weekday(s: &str) -> Option<Weekday> {
|
||||
let s = s.trim().to_lowercase();
|
||||
let s = s.as_str();
|
||||
|
||||
let parse_result: IResult<&str, Weekday> = nom::combinator::all_consuming(alt((
|
||||
tag_match!(Weekday::Mon, "monday", "mon"),
|
||||
tag_match!(Weekday::Tue, "tuesday", "tues", "tue"),
|
||||
tag_match!(Weekday::Wed, "wednesday", "wednes", "wed"),
|
||||
tag_match!(Weekday::Thu, "thursday", "thurs", "thur", "thu"),
|
||||
tag_match!(Weekday::Fri, "friday", "fri"),
|
||||
tag_match!(Weekday::Sat, "saturday", "sat"),
|
||||
tag_match!(Weekday::Sun, "sunday", "sun"),
|
||||
)))(s);
|
||||
|
||||
match parse_result {
|
||||
Ok((_, weekday)) => Some(weekday),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use chrono::Weekday::*;
|
||||
|
||||
use crate::parse_weekday::parse_weekday;
|
||||
|
||||
#[test]
|
||||
fn test_valid_weekdays() {
|
||||
let days = [
|
||||
("mon", Mon),
|
||||
("monday", Mon),
|
||||
("tue", Tue),
|
||||
("tues", Tue),
|
||||
("tuesday", Tue),
|
||||
("wed", Wed),
|
||||
("wednes", Wed),
|
||||
("wednesday", Wed),
|
||||
("thu", Thu),
|
||||
("thursday", Thu),
|
||||
("fri", Fri),
|
||||
("friday", Fri),
|
||||
("sat", Sat),
|
||||
("saturday", Sat),
|
||||
("sun", Sun),
|
||||
("sunday", Sun),
|
||||
];
|
||||
|
||||
for (name, weekday) in days {
|
||||
assert_eq!(parse_weekday(name), Some(weekday));
|
||||
assert_eq!(parse_weekday(&format!(" {}", name)), Some(weekday));
|
||||
assert_eq!(parse_weekday(&format!(" {} ", name)), Some(weekday));
|
||||
assert_eq!(parse_weekday(&format!("{} ", name)), Some(weekday));
|
||||
|
||||
let (left, right) = name.split_at(1);
|
||||
let (test_str1, test_str2) = (
|
||||
format!("{}{}", left.to_uppercase(), right.to_lowercase()),
|
||||
format!("{}{}", left.to_lowercase(), right.to_uppercase()),
|
||||
);
|
||||
|
||||
assert_eq!(parse_weekday(&test_str1), Some(weekday));
|
||||
assert_eq!(parse_weekday(&test_str2), Some(weekday));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_weekdays() {
|
||||
let days = [
|
||||
"mond",
|
||||
"tuesda",
|
||||
"we",
|
||||
"th",
|
||||
"fr",
|
||||
"sa",
|
||||
"su",
|
||||
"garbageday",
|
||||
"tomorrow",
|
||||
"yesterday",
|
||||
];
|
||||
for day in days {
|
||||
assert!(parse_weekday(day).is_none());
|
||||
}
|
||||
}
|
||||
}
|
||||
-136
@@ -1,137 +1 @@
|
||||
use humantime_to_duration::{from_str, ParseDurationError};
|
||||
use time::Duration;
|
||||
|
||||
#[test]
|
||||
fn test_invalid_input() {
|
||||
let result = from_str("foobar");
|
||||
println!("{result:?}");
|
||||
match result {
|
||||
Err(ParseDurationError::InvalidInput) => assert!(true),
|
||||
_ => assert!(false),
|
||||
}
|
||||
|
||||
let result = from_str("invalid 1");
|
||||
match result {
|
||||
Err(ParseDurationError::InvalidInput) => assert!(true),
|
||||
_ => assert!(false),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_duration_parsing() {
|
||||
assert_eq!(from_str("1 year").unwrap(), Duration::seconds(31_536_000));
|
||||
assert_eq!(
|
||||
from_str("-2 years").unwrap(),
|
||||
Duration::seconds(-63_072_000)
|
||||
);
|
||||
assert_eq!(
|
||||
from_str("2 years ago").unwrap(),
|
||||
Duration::seconds(-63_072_000)
|
||||
);
|
||||
assert_eq!(from_str("year").unwrap(), Duration::seconds(31_536_000));
|
||||
|
||||
assert_eq!(from_str("1 month").unwrap(), Duration::seconds(2_592_000));
|
||||
assert_eq!(
|
||||
from_str("1 month and 2 weeks").unwrap(),
|
||||
Duration::seconds(3_801_600)
|
||||
);
|
||||
assert_eq!(
|
||||
from_str("1 month, 2 weeks").unwrap(),
|
||||
Duration::seconds(3_801_600)
|
||||
);
|
||||
assert_eq!(
|
||||
from_str("1 months 2 weeks").unwrap(),
|
||||
Duration::seconds(3_801_600)
|
||||
);
|
||||
assert_eq!(
|
||||
from_str("1 month and 2 weeks ago").unwrap(),
|
||||
Duration::seconds(-3_801_600)
|
||||
);
|
||||
assert_eq!(from_str("2 months").unwrap(), Duration::seconds(5_184_000));
|
||||
assert_eq!(from_str("month").unwrap(), Duration::seconds(2_592_000));
|
||||
|
||||
assert_eq!(
|
||||
from_str("1 fortnight").unwrap(),
|
||||
Duration::seconds(1_209_600)
|
||||
);
|
||||
assert_eq!(
|
||||
from_str("3 fortnights").unwrap(),
|
||||
Duration::seconds(3_628_800)
|
||||
);
|
||||
assert_eq!(from_str("fortnight").unwrap(), Duration::seconds(1_209_600));
|
||||
|
||||
assert_eq!(from_str("1 week").unwrap(), Duration::seconds(604_800));
|
||||
assert_eq!(
|
||||
from_str("1 week 3 days").unwrap(),
|
||||
Duration::seconds(864_000)
|
||||
);
|
||||
assert_eq!(
|
||||
from_str("1 week 3 days ago").unwrap(),
|
||||
Duration::seconds(-864_000)
|
||||
);
|
||||
assert_eq!(from_str("-2 weeks").unwrap(), Duration::seconds(-1_209_600));
|
||||
assert_eq!(
|
||||
from_str("2 weeks ago").unwrap(),
|
||||
Duration::seconds(-1_209_600)
|
||||
);
|
||||
assert_eq!(from_str("week").unwrap(), Duration::seconds(604_800));
|
||||
|
||||
assert_eq!(from_str("1 day").unwrap(), Duration::seconds(86_400));
|
||||
assert_eq!(from_str("2 days ago").unwrap(), Duration::seconds(-172_800));
|
||||
assert_eq!(from_str("-2 days").unwrap(), Duration::seconds(-172_800));
|
||||
assert_eq!(from_str("day").unwrap(), Duration::seconds(86_400));
|
||||
|
||||
assert_eq!(from_str("1 hour").unwrap(), Duration::seconds(3_600));
|
||||
assert_eq!(from_str("1 h").unwrap(), Duration::seconds(3_600));
|
||||
assert_eq!(from_str("1 hour ago").unwrap(), Duration::seconds(-3_600));
|
||||
assert_eq!(from_str("-2 hours").unwrap(), Duration::seconds(-7_200));
|
||||
assert_eq!(from_str("hour").unwrap(), Duration::seconds(3_600));
|
||||
|
||||
assert_eq!(from_str("1 minute").unwrap(), Duration::seconds(60));
|
||||
assert_eq!(from_str("1 min").unwrap(), Duration::seconds(60));
|
||||
assert_eq!(from_str("2 minutes").unwrap(), Duration::seconds(120));
|
||||
assert_eq!(from_str("2 mins").unwrap(), Duration::seconds(120));
|
||||
assert_eq!(from_str("2m").unwrap(), Duration::seconds(120));
|
||||
assert_eq!(from_str("min").unwrap(), Duration::seconds(60));
|
||||
|
||||
assert_eq!(from_str("1 second").unwrap(), Duration::seconds(1));
|
||||
assert_eq!(from_str("1 s").unwrap(), Duration::seconds(1));
|
||||
assert_eq!(from_str("2 seconds").unwrap(), Duration::seconds(2));
|
||||
assert_eq!(from_str("2 secs").unwrap(), Duration::seconds(2));
|
||||
assert_eq!(from_str("2 sec").unwrap(), Duration::seconds(2));
|
||||
assert_eq!(from_str("sec").unwrap(), Duration::seconds(1));
|
||||
|
||||
assert_eq!(from_str("now").unwrap(), Duration::ZERO);
|
||||
assert_eq!(from_str("today").unwrap(), Duration::ZERO);
|
||||
|
||||
assert_eq!(
|
||||
from_str("1 year 2 months 4 weeks 3 days and 2 seconds").unwrap(),
|
||||
Duration::seconds(39_398_402)
|
||||
);
|
||||
assert_eq!(
|
||||
from_str("1 year 2 months 4 weeks 3 days and 2 seconds ago").unwrap(),
|
||||
Duration::seconds(-39_398_402)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_display_parse_duration_error_through_from_str() {
|
||||
let invalid_input = "9223372036854775807 seconds and 1 second";
|
||||
let error = from_str(invalid_input).unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
format!("{error}"),
|
||||
"Invalid input string: cannot be parsed as a relative time"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_display_should_fail() {
|
||||
let invalid_input = "Thu Jan 01 12:34:00 2015";
|
||||
let error = from_str(invalid_input).unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
format!("{error}"),
|
||||
"Invalid input string: cannot be parsed as a relative time"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user