120 Commits

Author SHA1 Message Date
Sylvestre Ledru 1552608bce Merge pull request #145 from yuankunzhang/fallible-offset-conversion
fallible offset conversion
2025-05-26 18:08:50 +02:00
Sylvestre Ledru ee9beb07d3 prepare release 0.10.0 2025-05-26 16:50:31 +02:00
Daniel Hofstetter 6f073addf5 Merge pull request #146 from drinkcat/fix-tests
Fix/improve tests
2025-05-26 13:59:44 +02:00
Nicolas Boichat a9676626be src/items: Fix timezone tests
The current tests look wrong ("%Z" shouldn't print an offset, but
this accidentally works due to the way the parsing logic operates),
fix that.
2025-05-25 21:34:22 +02:00
Nicolas Boichat da0af495e8 test: Replace %+ format with explicit one
%+ is an extension that jiff doesn't support (if we still want to
convert parse_datetime in the future, and since these are tests,
it's probably better to use an explicit format.
2025-05-25 21:34:22 +02:00
Nicolas Boichat e00555cd96 src/lib: Add end-to-end timezone test
Also make the offset test a little bit smarter.
2025-05-25 21:34:22 +02:00
yuankunzhang ab91b2b6d7 fallible offset conversion 2025-05-20 21:30:35 +08:00
Terts Diepraam cc7c143b21 Merge pull request #141 from yuankunzhang/main
Upgrade winnow to 0.7.10
2025-05-19 15:05:43 +02:00
Daniel Hofstetter 7721ae2cd8 Merge pull request #142 from yanganto/msrv
Specify MSRV 1.71.1
2025-05-14 16:06:27 +02:00
Antonio Yang 557c3a3ae3 Specify MSRV 1.71.1 2025-05-14 00:59:47 +08:00
yuankunzhang bea8ec2641 upgrade winnow to 0.7.10 2025-05-12 19:46:33 +08:00
Terts Diepraam 852e49e224 Merge pull request #138 from yuankunzhang/code-cleanup
Code cleanup
2025-05-09 13:31:02 +02:00
yuankunzhang 2390ef0b25 code cleanup 2025-05-09 18:55:10 +08:00
Terts Diepraam 77156f46d2 Merge pull request #137 from yuankunzhang/replace-the-regex-parser
Replace the regex parser with winnow-based parse
2025-05-09 11:35:48 +02:00
yuankunzhang bc6b70bc9e code fixup to pass all tests 2025-05-07 21:54:42 +08:00
Daniel Hilst 2479c61dd5 Find a compatibility intersection between chrono and GNU 2025-04-30 19:53:34 +08:00
Daniel Hilst 4c3d2221da Restore the old API and add the missing combinators 2025-04-30 19:53:34 +08:00
Terts Diepraam 07d4b80ea5 start parsing date with winnow 2025-04-30 19:53:34 +08:00
Daniel Hofstetter b481a2bdec Merge pull request #136 from uutils/renovate/chrono-0.x-lockfile
fix(deps): update rust crate chrono to v0.4.41
2025-04-29 18:28:41 +02:00
renovate[bot] a387463373 fix(deps): update rust crate chrono to v0.4.41 2025-04-29 15:59:06 +00:00
Daniel Hofstetter b6795d9b2e Merge pull request #134 from dan-hipschman/handle-uppercase
Allow uppercase for words like "today", "next", etc.
2025-04-26 17:56:24 +02:00
Dan Hipschman 3bdafeb2cf Allow uppercase for words like "today", "next", etc. 2025-04-26 08:07:10 -07:00
Daniel Hofstetter b9630d4bd3 Merge pull request #128 from dan-hipschman/parse-relative-weekdays
Parse relative weekdays like "next monday"
2025-04-25 09:24:49 +02:00
Dan Hipschman 65fb9140d2 Parse relative weekdays like "next monday" 2025-04-22 10:00:13 -07:00
Sylvestre Ledru 9b22a18bce Merge pull request #130 from cakebaker/fix_some_clippy_pedantic_issues
clippy: fix some warnings from clippy::pedantic
2025-04-22 10:42:20 +02:00
Daniel Hofstetter 28b788a300 clippy: fix warnings from redundant_else lint 2025-04-22 10:34:39 +02:00
Daniel Hofstetter f6b6b3e4ea clippy: fix warning from manual_let_else lint 2025-04-22 10:31:02 +02:00
Daniel Hofstetter 1a93bb4e3e clippy: fix warning from needless_continue lint 2025-04-22 10:27:13 +02:00
Daniel Hofstetter 9fc966308e clippy: remove unnecessary semicolon 2025-04-22 10:12:20 +02:00
Sylvestre Ledru 7119769488 Merge pull request #121 from cakebaker/rename_const
Rename `TWELVEHOUR` to `TWELVE_HOUR`
2025-04-22 09:56:39 +02:00
Daniel Hofstetter 46a82b70b3 Rename TWELVEHOUR to TWELVE_HOUR 2025-04-22 09:52:19 +02:00
Dan Hipschman e7ed14e8a4 Allow spaces between +/- and number (#129)
* Allow spaces between +/- and number

* Remove space to make fmt job pass

---------

Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com>
2025-04-22 09:44:09 +02:00
Daniel Hofstetter 9184428407 Merge pull request #126 from uutils/renovate/chrono-0.x-lockfile
Update Rust crate chrono to v0.4.40
2025-02-26 13:44:20 +01:00
renovate[bot] 25825df8b7 Update Rust crate chrono to v0.4.40 2025-02-26 11:56:48 +00:00
Sylvestre Ledru 0dbce58014 Merge pull request #120 from cakebaker/readme_fix_sentence
README.md: fix incorrect sentence
2025-02-17 20:31:53 +01:00
Daniel Hofstetter 0c0a054f70 README.md: fix incorrect sentence 2025-02-17 14:51:34 +01:00
Sylvestre Ledru 52dca03c56 README.md: adjust the doc to avoid the hardcoded version 2025-02-17 11:24:36 +01:00
Daniel Hofstetter d4384ceec9 Merge pull request #119 from sylvestre/new-release
Prepare the new relase + clippy
2025-02-17 08:58:27 +01:00
Sylvestre Ledru 46cc4147c7 fix clippy pedantic 2025-02-16 21:52:29 +01:00
Sylvestre Ledru 93e1c9bfe7 prepare 0.8.0 2025-02-16 21:32:13 +01:00
Daniel Hofstetter e7a7a0b07f Merge pull request #110 from jfinkels/parse-ref-date-and-delta
Parse reference datetime and timedelta from the same string
2025-02-16 17:20:29 +01:00
jfinkels d4353d0888 Use str.ends_with for patterns ending in Z
Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com>
2025-02-16 11:16:23 -05:00
Jeffrey Finkelstein 8aee979de5 Parse reference date and delta from same string
Change the `parse_datetime()` function so that it parses both a
reference date and a time delta from one string. The new implementation
attempts to parse the datetime from the longest possible prefix of the
string. The remainder of the string is parsed as the time delta. This
allows us to parse more combinations of reference dates and time deltas
more easily.

Fixes #104
2025-02-14 22:00:09 -05:00
Jeffrey Finkelstein f1fada62a6 Add additional pattern for datetime w/o timezone 2025-02-14 22:00:09 -05:00
Daniel Hofstetter ca6a39c0a7 Merge pull request #117 from jfinkels/add-time-to-date-after-parsing
Add time to parsed date after parsing not before
2025-02-14 10:10:14 +01:00
Jeffrey Finkelstein db18db4e1d Add time to parsed date after parsing not before
Change the way dates without times are parsed by just parsing the date
as-is and applying the placeholder time (00:00:00) after parsing
instead of before.
2025-02-13 18:48:47 -05:00
Sylvestre Ledru c337aba9cb Merge pull request #116 from jfinkels/remove-add-zero-months
Remove more useless calls to add zero months to date
2025-02-13 07:55:18 +01:00
Sylvestre Ledru 63cfc01e80 Merge pull request #111 from cakebaker/fuzz_remove_rand_dependency
fuzz: remove `rand` dependency
2025-02-13 07:54:53 +01:00
Sylvestre Ledru 1daaeb42a2 Merge pull request #118 from jfinkels/add-more-tests
Add a lot more unit tests
2025-02-13 07:54:36 +01:00
Jeffrey Finkelstein 3fcbac6fae Add a lot more unit tests
Add more unit tests for `parse_datetime()` when given an input without
a time delta (like "+1 year" or similar).
2025-02-12 22:04:09 -05:00
Jeffrey Finkelstein 65cd15dba9 Remove useless call to add zero months to date 2025-02-12 21:49:23 -05:00
Daniel Hofstetter 65c88f3586 Merge pull request #115 from jfinkels/patterns-with-length
Greedy parsing of datetime before time delta
2025-02-12 07:15:23 +01:00
jfinkels 2c55db21fa Avoid unnecessary slicing when parsing offset
Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com>
2025-02-11 20:05:55 -05:00
Jeffrey Finkelstein badc887606 Greedy parsing of datetime before time delta
Simulate greedy parsing of an absolute datetime in the prefix of a
string before parsing a subsequent time delta in the suffix of the
string. This does not change the behavior of `parse_datetime`, it just
prepares the code for a future change that allows parsing both the
absolute datetime and the time delta from the same string.

Greedy parsing is implemented by iterating over a list of patterns in
decreasing order of length so that longer patterns are tried before
shorter patterns. This guarantees that if there is an absolute datetime
present at the beginning of the string, then it will definitely be
parsed and the remaining part of the string is assumed to contain a time
delta.
2025-02-09 17:31:25 -05:00
Jeffrey Finkelstein f8adcb6c88 Add passing test for parsing datetime ending in Z
Add a passing unit test for parsing a datetime ending in the letter Z,
as in

    2023-06-03 12:00:01Z

This is treated as a datetime in the UTC time zone.
2025-02-09 17:31:25 -05:00
Daniel Hofstetter d0dceb6eaf Merge pull request #114 from jfinkels/parse-empty-string
Allow empty string in parse_relative_time_at_date
2025-02-09 16:18:43 +01:00
Jeffrey Finkelstein 45b9d9f09a Allow empty string in parse_relative_time_at_date
Allow the empty string when parsing the relative time in
`parse_relative_time_at_date()`. The empty string represents zero time
delta.
2025-02-08 15:05:50 -05:00
Daniel Hofstetter 0965130c1b fuzz: remove rand dependency 2025-02-08 20:59:19 +01:00
Sylvestre Ledru 51ddcb793f Merge pull request #113 from jfinkels/set-utc-tz-in-test
Explicitly set timezone UTC0 in a unit test
2025-02-08 20:59:03 +01:00
Sylvestre Ledru 7985aa04ba Merge pull request #112 from jfinkels/fix-add-months-tests
Make tests of adding months more resilient
2025-02-08 20:58:39 +01:00
Jeffrey Finkelstein 5c0c9c4405 Explicitly set timezone UTC0 in a unit test 2025-02-08 14:48:06 -05:00
Jeffrey Finkelstein 8dd8051eb7 Make tests of adding months more resilient
Protect against a situation where adding one month to the current day
would cause an overflow in the next month in some unit tests of
`parse_relative_time`. For example, adding one month to March 31
should overflow to May 1 because April only has 30 days. This is a
difference in the behavior we want for our library compared with the
behavior of `chrono`.
2025-02-08 14:42:38 -05:00
Daniel Hofstetter 073b9f7b70 Merge pull request #109 from uutils/renovate/libfuzzer-sys-0.x-lockfile
fix(deps): update rust crate libfuzzer-sys to v0.4.9
2025-01-29 07:16:20 +01:00
renovate[bot] 0318dabe3a fix(deps): update rust crate libfuzzer-sys to v0.4.9 2025-01-28 18:33:49 +00:00
Sylvestre Ledru 57fe123e21 Merge pull request #107 from cakebaker/bump_nom
Bump `nom` & adapt to API changes
2025-01-27 11:14:31 +01:00
Daniel Hofstetter 2fe83cabf1 Adapt to API changes in nom 8.0.0 2025-01-27 10:53:08 +01:00
Daniel Hofstetter 94d4112707 Bump nom from 7.1.3 to 8.0.0 2025-01-27 10:48:23 +01:00
Sylvestre Ledru eda2422bb3 Merge pull request #103 from jfinkels/parse-datetime-with-single-digit-offset-t-sep
Parse datetime with T separator and single digit offset
2025-01-19 23:07:12 +01:00
Jeffrey Finkelstein c948274c42 Parse datetime with T separator and digit offset
Parse a datetime with T separator between date and time, single digit
timezone offset, and no space between time and offset.
2025-01-19 16:38:06 -05:00
Sylvestre Ledru b209341259 Merge pull request #105 from sylvestre/0.7.0
prepare new release 0.7.0
2025-01-19 22:29:25 +01:00
Sylvestre Ledru 9cd22afa29 prepare new release 0.7.0 2025-01-19 22:25:25 +01:00
Sylvestre Ledru a7061bce12 Merge pull request #102 from jfinkels/parse-datetime-with-single-digit-offset
Parse datetimes with single digit timezone offset
2025-01-19 22:25:10 +01:00
Jeffrey Finkelstein ea49dc94f0 Parse datetimes with single digit timezone offset
Parse full datetimes with single digit timezone offsets like +3 or -5.
2025-01-18 18:45:22 -05:00
Sylvestre Ledru 938aa9694b Merge pull request #100 from jfinkels/add-months-overflow-surplus-days
Overflow surplus days when adding months to a date
2025-01-18 23:30:10 +01:00
Sylvestre Ledru 51e294724c Merge pull request #99 from jfinkels/parse-dates-with-slashes
Parse calendar dates with slashes, like 2/29/1996
2025-01-18 23:27:22 +01:00
Sylvestre Ledru fa53ec79bd Merge pull request #78 from cakebaker/readme_bump_version
readme: bump version to 0.6.0
2025-01-18 23:27:02 +01:00
Jeffrey Finkelstein 90d22a2c37 Overflow surplus days when adding months to a date
Change the behavior of `parse_relative_time_at_date()` so that adding
months to a given date causes surplus days to overflow to the next
month. For example, adding 1 month to 1996-03-31 would be 1996-04-31,
but April only has 30 days, so the surplus day rolls over to the next
month, resulting in 1996-05-01.

Closes #98
2025-01-18 23:23:37 +01:00
Jeffrey Finkelstein 06aac3f56f Parse calendar dates with slashes, like 2/29/1996 2025-01-18 23:23:34 +01:00
Sylvestre Ledru 240abf791e Merge pull request #101 from jfinkels/single-digit-tz-offset
Parse single digit timezone offsets
2025-01-18 23:22:50 +01:00
Jeffrey Finkelstein 34f226fd98 Parse single digit timezone offsets
Add parsing for timezone offsets of the form +N or -N. As a side effect
of this change, parsing timezone offsets like +0700, UTC+2, and Z-1 are
now supported.
2025-01-18 14:49:16 -05:00
Sylvestre Ledru 00dc90dd10 Merge pull request #97 from jfinkels/military-time-zones
Add support for military time zones
2025-01-09 07:51:39 +01:00
Jeffrey Finkelstein 3c67f4b5c9 Add support for military time zones
Fixes #39
2025-01-08 21:38:46 -05:00
Daniel Hofstetter faf363c2e6 Merge pull request #96 from uutils/renovate/chrono-0.x-lockfile
fix(deps): update rust crate chrono to v0.4.39
2024-12-09 13:34:01 +01:00
renovate[bot] 56410cebcf fix(deps): update rust crate chrono to v0.4.39 2024-12-09 12:12:42 +00:00
Daniel Hofstetter d777be1bb6 Merge pull request #94 from uutils/renovate/migrate-config
chore(config): migrate renovate config
2024-11-29 16:05:53 +01:00
Daniel Hofstetter 6429ef26c5 Merge pull request #93 from uutils/renovate/codecov-codecov-action-5.x
chore(deps): update codecov/codecov-action action to v5
2024-11-29 16:03:30 +01:00
Daniel Hofstetter fa311c0dd4 ci: fix deprecated codecov argument 2024-11-29 15:59:28 +01:00
renovate[bot] 7ab9a02761 chore(deps): update codecov/codecov-action action to v5 2024-11-29 14:49:20 +00:00
Sylvestre Ledru 78877a1b98 Merge pull request #92 from cakebaker/ci_fix_code_coverage
ci: use `-Cinstrument-coverage` instead of `-Zprofile`
2024-11-29 15:49:10 +01:00
Sylvestre Ledru 623c626b3a Merge pull request #95 from cakebaker/clippy_fix_warning
clippy: fix warning from `needless_return` lint
2024-11-29 09:53:27 +01:00
Daniel Hofstetter a9bccfa20a clippy: fix warning from needless_return lint 2024-11-29 09:44:40 +01:00
renovate[bot] dba1374f8e chore(config): migrate config renovate.json 2024-11-18 14:38:21 +00:00
Daniel Hofstetter 9b266bcb17 ci: use -Cinstrument-coverage instead of -Zprofile
Support for -Zprofile has been removed: https://github.com/rust-lang/rust/pull/131829
2024-11-11 09:48:09 +01:00
Sylvestre Ledru 5e3fc539a3 Merge pull request #88 from cakebaker/bump_iana_time_zone_in_fuzz
Bump `iana-time-zone` in `fuzz` from `0.1.56` to `0.1.61`
2024-11-08 10:28:05 +01:00
Sylvestre Ledru c26d83fd6e Merge pull request #91 from uutils/renovate/libfuzzer-sys-0.x-lockfile
fix(deps): update rust crate libfuzzer-sys to v0.4.8
2024-11-08 10:27:56 +01:00
renovate[bot] a841ad0fc4 fix(deps): update rust crate libfuzzer-sys to v0.4.8 2024-11-08 01:44:41 +00:00
Daniel Hofstetter 8ca89bdb55 Merge pull request #90 from uutils/renovate/regex-1.x-lockfile
fix(deps): update rust crate regex to v1.11.1
2024-10-25 07:06:26 +02:00
renovate[bot] 48852068de fix(deps): update rust crate regex to v1.11.1 2024-10-24 17:07:28 +00:00
Daniel Hofstetter 3813a3bae9 Merge pull request #89 from uutils/renovate/regex-1.x-lockfile
fix(deps): update rust crate regex to v1.11.0
2024-09-30 06:59:39 +02:00
renovate[bot] 313de7ba7c fix(deps): update rust crate regex to v1.11.0 2024-09-29 16:46:09 +00:00
Daniel Hofstetter 7913ecd888 Merge pull request #87 from jetlime/main
`parse_relative_time`: Include 'this' direction
2024-09-17 16:11:30 +02:00
Paul Houssel 8a528468ae include 'this' direction 2024-09-17 15:31:00 +02:00
Daniel Hofstetter 212c6f7c24 Merge pull request #85 from ysthakur/fix-relative-time
Don't use Durations for calculating relative times
2024-09-17 11:06:59 +02:00
Daniel Hofstetter cd7020f038 Bump iana-time-zone in fuzz from 0.1.56 to 0.1.61 2024-09-17 09:49:38 +02:00
Daniel Hofstetter e543ee64a7 Merge pull request #75 from uutils/renovate/chrono-0.x-lockfile
fix(deps): update rust crate chrono to v0.4.38
2024-09-17 09:43:55 +02:00
renovate[bot] 19d49cfe73 fix(deps): update rust crate chrono to v0.4.38 2024-09-17 07:39:50 +00:00
Sylvestre Ledru 86d72fc867 Merge pull request #74 from cakebaker/bump_chrono
Bump `chrono` and `iana-time-zone`; fix use of deprecated function
2024-09-17 09:38:40 +02:00
Daniel Hofstetter bbcafc42f9 Replace use of NativeDateTime::from_timestamp_opt
with DateTime::from_timestamp due to deprecation
2024-09-17 09:34:25 +02:00
Daniel Hofstetter 1570d92fc5 Bump chrono and iana-time-zone
chrono: 0.4.26 -> 0.4.38
iana-time-zone: 0.1.56 -> 0.1.61
2024-09-17 09:34:14 +02:00
ysthakur e41e26fef1 Replace unnecessary return with None 2024-09-04 23:55:47 -04:00
ysthakur d5015a641e Format 2024-08-28 02:24:49 -04:00
ysthakur 5e6bddb6f5 Get rid of parse_relative_time 2024-08-27 22:13:47 -04:00
ysthakur ced645a4f4 Make helpers timezone-generic 2024-08-27 21:46:49 -04:00
ysthakur d75338a51b Make tests for months without 30 days and leap years 2024-08-27 19:02:08 -04:00
ysthakur d4f67bbde0 Don't use Durations for calculating relative times 2024-08-27 18:51:10 -04:00
Daniel Hofstetter ba19b94acd Merge pull request #81 from uutils/renovate/regex-1.x-lockfile
fix(deps): update rust crate regex to v1.10.6
2024-08-02 18:32:25 +02:00
renovate[bot] f7f789913a fix(deps): update rust crate regex to v1.10.6 2024-08-02 16:04:11 +00:00
Daniel Hofstetter 7e84a62b9e Merge pull request #79 from uutils/renovate/regex-1.x-lockfile
fix(deps): update rust crate regex to v1.10.5
2024-06-09 15:59:12 +02:00
renovate[bot] db8c1d364f fix(deps): update rust crate regex to v1.10.5 2024-06-09 13:29:07 +00:00
Daniel Hofstetter e1aa18d263 readme: bump version to 0.6.0 2024-05-21 07:22:43 +02:00
19 changed files with 2755 additions and 1442 deletions
+23 -9
View File
@@ -4,6 +4,7 @@ name: Basic CI
env:
CARGO_TERM_COLOR: always
RUST_MIN_SRV: "1.71.1"
jobs:
check:
@@ -49,6 +50,19 @@ jobs:
- run: rustup component add clippy
- run: cargo clippy --all-targets -- -D warnings
min_version:
name: Minimum Supported Rust Version
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macOS-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ env.RUST_MIN_SRV }}
- run: cargo test
coverage:
name: Code Coverage
runs-on: ${{ matrix.job.os }}
@@ -75,21 +89,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: dtolnay/rust-toolchain@nightly
with:
components: llvm-tools-preview
- name: Test
run: cargo test ${{ 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
@@ -117,16 +132,15 @@ 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@v4
# if: steps.vars.outputs.HAS_CODECOV_TOKEN
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ${{ steps.coverage.outputs.report }}
files: ${{ steps.coverage.outputs.report }}
## flags: IntegrationTests, UnitTests, ${{ steps.vars.outputs.CODECOV_FLAGS }}
flags: ${{ steps.vars.outputs.CODECOV_FLAGS }}
name: codecov-umbrella
Generated
+132 -146
View File
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "aho-corasick"
version = "1.0.1"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
@@ -28,21 +28,24 @@ dependencies = [
[[package]]
name = "autocfg"
version = "1.1.0"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "bumpalo"
version = "3.13.0"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "cc"
version = "1.0.79"
version = "1.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
@@ -52,34 +55,35 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.26"
version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits",
"winapi",
"windows-link",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.4"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "iana-time-zone"
version = "0.1.56"
version = "0.1.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows",
"windows-core",
]
[[package]]
@@ -93,94 +97,80 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.63"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "libc"
version = "0.2.144"
version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "log"
version = "0.4.18"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "memchr"
version = "2.6.4"
version = "2.7.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",
]
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "num-traits"
version = "0.2.15"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.18.0"
version = "1.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
[[package]]
name = "parse_datetime"
version = "0.6.0"
version = "0.10.0"
dependencies = [
"chrono",
"nom",
"num-traits",
"regex",
"winnow",
]
[[package]]
name = "proc-macro2"
version = "1.0.59"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.28"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.10.4"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
@@ -190,9 +180,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.6"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [
"aho-corasick",
"memchr",
@@ -201,15 +191,27 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.8.3"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "rustversion"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
version = "2.0.18"
version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
@@ -218,29 +220,30 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.9"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "wasm-bindgen"
version = "0.2.86"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.86"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
@@ -249,9 +252,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.86"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -259,9 +262,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.86"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
@@ -272,94 +275,77 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.86"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
"unicode-ident",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
name = "windows-core"
version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-interface"
version = "0.59.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "windows-link"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
[[package]]
name = "windows-result"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
dependencies = [
"windows-targets",
"windows-link",
]
[[package]]
name = "windows-targets"
version = "0.48.0"
name = "winnow"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"memchr",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+5 -3
View File
@@ -1,13 +1,15 @@
[package]
name = "parse_datetime"
description = "parsing human-readable time strings and converting them to a DateTime"
version = "0.6.0"
version = "0.10.0"
edition = "2021"
license = "MIT"
repository = "https://github.com/uutils/parse_datetime"
readme = "README.md"
rust-version = "1.71.1"
[dependencies]
regex = "1.10.4"
chrono = { version="0.4", default-features=false, features=["std", "alloc", "clock"] }
nom = "7.1.3"
chrono = { version="0.4.38", default-features=false, features=["std", "alloc", "clock"] }
winnow = "0.7.10"
num-traits = "0.2.19"
+3 -4
View File
@@ -16,11 +16,10 @@ A Rust crate for parsing human-readable relative time strings and human-readable
## Usage
Add this to your `Cargo.toml`:
Add `parse_datetime` to your `Cargo.toml` with:
```toml
[dependencies]
parse_datetime = "0.5.0"
```
cargo add parse_datetime
```
Then, import the crate and use the `parse_datetime_at_date` function:
+87 -148
View File
@@ -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"
@@ -46,11 +46,13 @@ checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
name = "cc"
version = "1.0.79"
version = "1.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
dependencies = [
"jobserver",
"libc",
"shlex",
]
[[package]]
@@ -61,14 +63,14 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.26"
version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits",
"winapi",
"windows-link",
]
[[package]]
@@ -84,33 +86,21 @@ dependencies = [
"chrono",
"libfuzzer-sys",
"parse_datetime",
"rand",
"regex",
]
[[package]]
name = "getrandom"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "iana-time-zone"
version = "0.1.56"
version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows",
"windows-core",
]
[[package]]
@@ -124,18 +114,18 @@ dependencies = [
[[package]]
name = "jobserver"
version = "0.1.26"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
[[package]]
name = "js-sys"
version = "0.3.63"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
"wasm-bindgen",
]
@@ -148,13 +138,12 @@ checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
[[package]]
name = "libfuzzer-sys"
version = "0.4.7"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7"
checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75"
dependencies = [
"arbitrary",
"cc",
"once_cell",
]
[[package]]
@@ -169,27 +158,11 @@ 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"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
@@ -202,19 +175,14 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "parse_datetime"
version = "0.5.0"
version = "0.10.0"
dependencies = [
"chrono",
"nom",
"num-traits",
"regex",
"winnow",
]
[[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"
@@ -233,41 +201,11 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "regex"
version = "1.10.4"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [
"aho-corasick",
"memchr",
@@ -277,9 +215,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.4"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a"
checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
dependencies = [
"aho-corasick",
"memchr",
@@ -288,9 +226,15 @@ dependencies = [
[[package]]
name = "regex-syntax"
version = "0.8.2"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "syn"
@@ -309,27 +253,22 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
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.86"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
dependencies = [
"cfg-if",
"once_cell",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.86"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
dependencies = [
"bumpalo",
"log",
@@ -342,9 +281,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.86"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -352,9 +291,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.86"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [
"proc-macro2",
"quote",
@@ -365,50 +304,35 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.86"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
[[package]]
name = "winapi"
version = "0.3.9"
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.0"
name = "windows-link"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
[[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",
@@ -417,42 +341,57 @@ dependencies = [
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
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.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
dependencies = [
"memchr",
]
-1
View File
@@ -7,7 +7,6 @@ edition = "2021"
cargo-fuzz = true
[dependencies]
rand = "0.8.5"
libfuzzer-sys = "0.4.7"
regex = "1.10.4"
chrono = { version="0.4", default-features=false, features=["std", "alloc", "clock"] }
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
"config:recommended"
]
}
+78
View File
@@ -0,0 +1,78 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//! Parse an ISO 8601 date and time item
//!
//! The GNU docs state:
//!
//! > The ISO 8601 date and time of day extended format consists of an ISO 8601
//! > date, a T character separator, and an ISO 8601 time of day. This format
//! > is also recognized if the T is replaced by a space.
//! >
//! > In this format, the time of day should use 24-hour notation. Fractional
//! > seconds are allowed, with either comma or period preceding the fraction.
//! > ISO 8601 fractional minutes and hours are not supported. Typically, hosts
//! > support nanosecond timestamp resolution; excess precision is silently discarded.
use winnow::{
combinator::{alt, trace},
seq, ModalResult, Parser,
};
use crate::items::space;
use super::{
date::{self, Date},
s,
time::{self, Time},
};
#[derive(PartialEq, Debug, Clone, Default)]
pub struct DateTime {
pub(crate) date: Date,
pub(crate) time: Time,
}
pub fn parse(input: &mut &str) -> ModalResult<DateTime> {
seq!(DateTime {
date: trace("date iso", alt((date::iso1, date::iso2))),
// Note: the `T` is lowercased by the main parse function
_: alt((s('t').void(), (' ', space).void())),
time: trace("time iso", time::iso),
})
.parse_next(input)
}
#[cfg(test)]
mod tests {
use super::{parse, DateTime};
use crate::items::{date::Date, time::Time};
#[test]
fn some_date() {
let reference = Some(DateTime {
date: Date {
day: 10,
month: 10,
year: Some(2022),
},
time: Time {
hour: 10,
minute: 10,
second: 55.0,
offset: None,
},
});
for mut s in [
"2022-10-10t10:10:55",
"2022-10-10 10:10:55",
"2022-10-10 t 10:10:55",
"2022-10-10 10:10:55",
"2022-10-10 (A comment!) t 10:10:55",
"2022-10-10 (A comment!) 10:10:55",
] {
let old_s = s.to_owned();
assert_eq!(parse(&mut s).ok(), reference, "Failed string: {old_s}")
}
}
}
+284
View File
@@ -0,0 +1,284 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//! Parse a date item (without time component)
//!
//! The GNU docs say:
//!
//! > A calendar date item specifies a day of the year. It is specified
//! > differently, depending on whether the month is specified numerically
//! > or literally.
//! >
//! > ...
//! >
//! > For numeric months, the ISO 8601 format year-month-day is allowed,
//! > where year is any positive number, month is a number between 01 and
//! > 12, and day is a number between 01 and 31. A leading zero must be
//! > present if a number is less than ten. If year is 68 or smaller, then
//! > 2000 is added to it; otherwise, if year is less than 100, then 1900
//! > is added to it. The construct month/day/year, popular in the United
//! > States, is accepted. Also month/day, omitting the year.
//! >
//! > Literal months may be spelled out in full: January, February,
//! > March, April, May, June, July, August, September,
//! > October, November or December. Literal months may be
//! > abbreviated to their first three letters, possibly followed by an
//! > abbreviating dot. It is also permitted to write Sept instead of
//! > September.
use winnow::{
ascii::alpha1,
combinator::{alt, opt, preceded, trace},
seq,
stream::AsChar,
token::{take, take_while},
ModalResult, Parser,
};
use super::{dec_uint, s};
use crate::ParseDateTimeError;
#[derive(PartialEq, Eq, Clone, Debug, Default)]
pub struct Date {
pub day: u32,
pub month: u32,
pub year: Option<u32>,
}
pub fn parse(input: &mut &str) -> ModalResult<Date> {
alt((iso1, iso2, us, literal1, literal2)).parse_next(input)
}
/// Parse `YYYY-MM-DD` or `YY-MM-DD`
///
/// This is also used by [`combined`](super::combined).
pub fn iso1(input: &mut &str) -> ModalResult<Date> {
seq!(Date {
year: year.map(Some),
_: s('-'),
month: month,
_: s('-'),
day: day,
})
.parse_next(input)
}
/// Parse `YYYYMMDD`
///
/// This is also used by [`combined`](super::combined).
pub fn iso2(input: &mut &str) -> ModalResult<Date> {
s((
take(4usize).try_map(|s: &str| s.parse::<u32>()),
take(2usize).try_map(|s: &str| s.parse::<u32>()),
take(2usize).try_map(|s: &str| s.parse::<u32>()),
))
.map(|(year, month, day): (u32, u32, u32)| Date {
day,
month,
year: Some(year),
})
.parse_next(input)
}
/// Parse `MM/DD/YYYY`, `MM/DD/YY` or `MM/DD`
fn us(input: &mut &str) -> ModalResult<Date> {
seq!(Date {
month: month,
_: s('/'),
day: day,
year: opt(preceded(s('/'), year)),
})
.parse_next(input)
}
/// Parse `14 November 2022`, `14 Nov 2022`, "14nov2022", "14-nov-2022", "14-nov2022", "14nov-2022"
fn literal1(input: &mut &str) -> ModalResult<Date> {
seq!(Date {
day: day,
_: opt(s('-')),
month: literal_month,
year: opt(preceded(opt(s('-')), year)),
})
.parse_next(input)
}
/// Parse `November 14, 2022` and `Nov 14, 2022`
fn literal2(input: &mut &str) -> ModalResult<Date> {
seq!(Date {
month: literal_month,
day: day,
// FIXME: GNU requires _some_ space between the day and the year,
// probably to distinguish with floats.
year: opt(preceded(s(","), year)),
})
.parse_next(input)
}
pub fn year(input: &mut &str) -> ModalResult<u32> {
// 2147485547 is the maximum value accepted
// by GNU, but chrono only behaves like GNU
// for years in the range: [0, 9999], so we
// keep in the range [0, 9999]
trace(
"year",
s(
take_while(1..=4, AsChar::is_dec_digit).map(|number_str: &str| {
let year = number_str.parse::<u32>().unwrap();
if number_str.len() == 2 {
if year <= 68 {
year + 2000
} else {
year + 1900
}
} else {
year
}
}),
),
)
.parse_next(input)
}
fn month(input: &mut &str) -> ModalResult<u32> {
s(dec_uint)
.try_map(|x| {
(1..=12)
.contains(&x)
.then_some(x)
.ok_or(ParseDateTimeError::InvalidInput)
})
.parse_next(input)
}
fn day(input: &mut &str) -> ModalResult<u32> {
s(dec_uint)
.try_map(|x| {
(1..=31)
.contains(&x)
.then_some(x)
.ok_or(ParseDateTimeError::InvalidInput)
})
.parse_next(input)
}
/// Parse the name of a month (case-insensitive)
fn literal_month(input: &mut &str) -> ModalResult<u32> {
s(alpha1)
.verify_map(|s: &str| {
Some(match s {
"january" | "jan" => 1,
"february" | "feb" => 2,
"march" | "mar" => 3,
"april" | "apr" => 4,
"may" => 5,
"june" | "jun" => 6,
"july" | "jul" => 7,
"august" | "aug" => 8,
"september" | "sep" | "sept" => 9,
"october" | "oct" => 10,
"november" | "nov" => 11,
"december" | "dec" => 12,
_ => return None,
})
})
.parse_next(input)
}
#[cfg(test)]
mod tests {
use super::{parse, Date};
// Test cases from the GNU docs:
//
// ```
// 2022-11-14 # ISO 8601.
// 22-11-14 # Assume 19xx for 69 through 99,
// # 20xx for 00 through 68 (not recommended).
// 11/14/2022 # Common U.S. writing.
// 14 November 2022
// 14 Nov 2022 # Three-letter abbreviations always allowed.
// November 14, 2022
// 14-nov-2022
// 14nov2022
// ```
#[test]
fn with_year() {
let reference = Date {
year: Some(2022),
month: 11,
day: 14,
};
for mut s in [
"2022-11-14",
"2022 - 11 - 14",
"22-11-14",
"2022---11----14",
"22(comment 1)-11(comment 2)-14",
"11/14/2022",
"11--/14--/2022",
"11(comment 1)/(comment 2)14(comment 3)/(comment 4)2022",
"11 / 14 / 2022",
"11/14/22",
"14 november 2022",
"14 nov 2022",
"november 14, 2022",
"november 14 , 2022",
"nov 14, 2022",
"14-nov-2022",
"14nov2022",
"14nov 2022",
] {
let old_s = s.to_owned();
assert_eq!(parse(&mut s).unwrap(), reference, "Format string: {old_s}");
}
}
#[test]
fn no_year() {
let reference = Date {
year: None,
month: 11,
day: 14,
};
for mut s in [
"11/14",
"14 november",
"14 nov",
"14(comment!)nov",
"november 14",
"november(comment!)14",
"nov 14",
"14-nov",
"14nov",
"14(comment????)nov",
] {
assert_eq!(parse(&mut s).unwrap(), reference);
}
}
#[test]
fn test_year() {
use super::year;
// the minimun input length is 2
// assert!(year(&mut "0").is_err());
// -> GNU accepts year 0
// test $(date -d '1-1-1' '+%Y') -eq '0001'
// test $(date -d '68-1-1' '+%Y') -eq '2068'
// 2-characters are converted to 19XX/20XX
assert_eq!(year(&mut "10").unwrap(), 2010u32);
assert_eq!(year(&mut "68").unwrap(), 2068u32);
assert_eq!(year(&mut "69").unwrap(), 1969u32);
assert_eq!(year(&mut "99").unwrap(), 1999u32);
// 3,4-characters are converted verbatim
assert_eq!(year(&mut "468").unwrap(), 468u32);
assert_eq!(year(&mut "469").unwrap(), 469u32);
assert_eq!(year(&mut "1568").unwrap(), 1568u32);
assert_eq!(year(&mut "1569").unwrap(), 1569u32);
// consumes at most 4 characters from the input
//assert_eq!(year(&mut "1234567").unwrap(), 1234u32);
}
}
+543
View File
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use super::s;
use winnow::{
ascii::{alpha1, dec_uint},
combinator::{alt, opt},
ModalResult, Parser,
};
pub fn ordinal(input: &mut &str) -> ModalResult<i32> {
alt((text_ordinal, number_ordinal)).parse_next(input)
}
fn number_ordinal(input: &mut &str) -> ModalResult<i32> {
let sign = opt(alt(('+'.value(1), '-'.value(-1)))).map(|s| s.unwrap_or(1));
(s(sign), s(dec_uint))
.verify_map(|(s, u): (i32, u32)| {
let i: i32 = u.try_into().ok()?;
Some(s * i)
})
.parse_next(input)
}
fn text_ordinal(input: &mut &str) -> ModalResult<i32> {
s(alpha1)
.verify_map(|s: &str| {
Some(match s {
"last" => -1,
"this" => 0,
"next" | "first" => 1,
"third" => 3,
"fourth" => 4,
"fifth" => 5,
"sixth" => 6,
"seventh" => 7,
"eight" => 8,
"ninth" => 9,
"tenth" => 10,
"eleventh" => 11,
"twelfth" => 12,
_ => return None,
})
})
.parse_next(input)
}
+190
View File
@@ -0,0 +1,190 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//! Parse a relative datetime item
//!
//! The GNU docs state:
//!
//! > The unit of time displacement may be selected by the string year or
//! > month for moving by whole years or months. These are fuzzy units, as
//! > years and months are not all of equal duration. More precise units are
//! > fortnight which is worth 14 days, week worth 7 days, day worth 24
//! > hours, hour worth 60 minutes, minute or min worth 60 seconds, and
//! > second or sec worth one second. An s suffix on these units is
//! > accepted and ignored.
//! >
//! > The unit of time may be preceded by a multiplier, given as an optionally
//! > signed number. Unsigned numbers are taken as positively signed. No number
//! > at all implies 1 for a multiplier. Following a relative item by the
//! > string ago is equivalent to preceding the unit by a multiplier with
//! > value -1.
//! >
//! > The string tomorrow is worth one day in the future (equivalent to
//! > day), the string yesterday is worth one day in the past (equivalent
//! > to day ago).
//! >
//! > The strings now or today are relative items corresponding to
//! > zero-valued time displacement, these strings come from the fact a
//! > zero-valued time displacement represents the current time when not
//! > otherwise changed by previous items. They may be used to stress other
//! > items, like in 12:00 today. The string this also has the meaning of a
//! > zero-valued time displacement, but is preferred in date strings like
//! > this thursday.
use winnow::{
ascii::{alpha1, float},
combinator::{alt, opt},
ModalResult, Parser,
};
use super::{ordinal::ordinal, s};
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Relative {
Years(i32),
Months(i32),
Days(i32),
Hours(i32),
Minutes(i32),
// Seconds are special because they can be given as a float
Seconds(f64),
}
impl Relative {
fn mul(self, n: i32) -> Self {
match self {
Self::Years(x) => Self::Years(n * x),
Self::Months(x) => Self::Months(n * x),
Self::Days(x) => Self::Days(n * x),
Self::Hours(x) => Self::Hours(n * x),
Self::Minutes(x) => Self::Minutes(n * x),
Self::Seconds(x) => Self::Seconds(f64::from(n) * x),
}
}
}
pub fn parse(input: &mut &str) -> ModalResult<Relative> {
alt((
s("tomorrow").value(Relative::Days(1)),
s("yesterday").value(Relative::Days(-1)),
// For "today" and "now", the unit is arbitrary
s("today").value(Relative::Days(0)),
s("now").value(Relative::Days(0)),
seconds,
other,
))
.parse_next(input)
}
fn seconds(input: &mut &str) -> ModalResult<Relative> {
(
opt(alt((s(float), ordinal.map(|x| x as f64)))),
s(alpha1).verify(|s: &str| matches!(s, "seconds" | "second" | "sec" | "secs")),
ago,
)
.map(|(n, _, ago)| Relative::Seconds(n.unwrap_or(1.0) * if ago { -1.0 } else { 1.0 }))
.parse_next(input)
}
fn other(input: &mut &str) -> ModalResult<Relative> {
(opt(ordinal), integer_unit, ago)
.map(|(n, unit, ago)| unit.mul(n.unwrap_or(1) * if ago { -1 } else { 1 }))
.parse_next(input)
}
fn ago(input: &mut &str) -> ModalResult<bool> {
opt(s("ago")).map(|o| o.is_some()).parse_next(input)
}
fn integer_unit(input: &mut &str) -> ModalResult<Relative> {
s(alpha1)
.verify_map(|s: &str| {
Some(match s.strip_suffix('s').unwrap_or(s) {
"year" => Relative::Years(1),
"month" => Relative::Months(1),
"fortnight" => Relative::Days(14),
"week" => Relative::Days(7),
"day" => Relative::Days(1),
"hour" => Relative::Hours(1),
"minute" | "min" => Relative::Minutes(1),
_ => return None,
})
})
.parse_next(input)
}
#[cfg(test)]
mod tests {
use super::{parse, Relative};
#[test]
fn all() {
for (s, rel) in [
// Seconds
("second", Relative::Seconds(1.0)),
("sec", Relative::Seconds(1.0)),
("seconds", Relative::Seconds(1.0)),
("secs", Relative::Seconds(1.0)),
("second ago", Relative::Seconds(-1.0)),
("3 seconds", Relative::Seconds(3.0)),
("3.5 seconds", Relative::Seconds(3.5)),
// ("+3.5 seconds", Relative::Seconds(3.5)),
("3.5 seconds ago", Relative::Seconds(-3.5)),
("-3.5 seconds ago", Relative::Seconds(3.5)),
// Minutes
("minute", Relative::Minutes(1)),
("minutes", Relative::Minutes(1)),
("min", Relative::Minutes(1)),
("mins", Relative::Minutes(1)),
("10 minutes", Relative::Minutes(10)),
("-10 minutes", Relative::Minutes(-10)),
("10 minutes ago", Relative::Minutes(-10)),
("-10 minutes ago", Relative::Minutes(10)),
// Hours
("hour", Relative::Hours(1)),
("hours", Relative::Hours(1)),
("10 hours", Relative::Hours(10)),
("+10 hours", Relative::Hours(10)),
("-10 hours", Relative::Hours(-10)),
("10 hours ago", Relative::Hours(-10)),
("-10 hours ago", Relative::Hours(10)),
// Days
("day", Relative::Days(1)),
("days", Relative::Days(1)),
("10 days", Relative::Days(10)),
("+10 days", Relative::Days(10)),
("-10 days", Relative::Days(-10)),
("10 days ago", Relative::Days(-10)),
("-10 days ago", Relative::Days(10)),
// Multiple days
("fortnight", Relative::Days(14)),
("fortnights", Relative::Days(14)),
("2 fortnights ago", Relative::Days(-28)),
("+2 fortnights ago", Relative::Days(-28)),
("week", Relative::Days(7)),
("weeks", Relative::Days(7)),
("2 weeks ago", Relative::Days(-14)),
// Other
("year", Relative::Years(1)),
("years", Relative::Years(1)),
("month", Relative::Months(1)),
("months", Relative::Months(1)),
// Special
("yesterday", Relative::Days(-1)),
("tomorrow", Relative::Days(1)),
("today", Relative::Days(0)),
("now", Relative::Days(0)),
// This something
("this day", Relative::Days(0)),
("this second", Relative::Seconds(0.0)),
("this year", Relative::Years(0)),
// Weird stuff
("next week ago", Relative::Days(-7)),
("last week ago", Relative::Days(7)),
("this week ago", Relative::Days(0)),
] {
let mut t = s;
assert_eq!(parse(&mut t).ok(), Some(rel), "Failed string: {s}")
}
}
}
+853
View File
File diff suppressed because it is too large Load Diff
+137
View File
@@ -0,0 +1,137 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
// spell-checker:ignore wednes
//! The GNU docs state:
//!
//! > The explicit mention of a day of the week will forward the date (only if
//! > necessary) to reach that day of the week in the future.
//! >
//! > Days of the week may be spelled out in full: Sunday, Monday,
//! > Tuesday, Wednesday, Thursday, Friday or Saturday. Days may be
//! > abbreviated to their first three letters, optionally followed by a
//! > period. The special abbreviations Tues for Tuesday, Wednes for
//! > Wednesday and Thur or Thurs for Thursday are also allowed.
//! >
//! > A number may precede a day of the week item to move forward supplementary
//! > weeks. It is best used in expression like third monday. In this
//! > context, last day or next day is also acceptable; they move one week
//! > before or after the day that day by itself would represent.
//! >
//! > A comma following a day of the week item is ignored.
use winnow::{ascii::alpha1, combinator::opt, seq, ModalResult, Parser};
use super::{ordinal::ordinal, s};
#[derive(PartialEq, Eq, Debug)]
pub(crate) enum Day {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
}
#[derive(PartialEq, Eq, Debug)]
pub struct Weekday {
pub(crate) offset: i32,
pub(crate) day: Day,
}
impl From<Day> for chrono::Weekday {
fn from(value: Day) -> Self {
match value {
Day::Monday => chrono::Weekday::Mon,
Day::Tuesday => chrono::Weekday::Tue,
Day::Wednesday => chrono::Weekday::Wed,
Day::Thursday => chrono::Weekday::Thu,
Day::Friday => chrono::Weekday::Fri,
Day::Saturday => chrono::Weekday::Sat,
Day::Sunday => chrono::Weekday::Sun,
}
}
}
pub fn parse(input: &mut &str) -> ModalResult<Weekday> {
seq!(Weekday {
offset: opt(ordinal).map(|o| o.unwrap_or_default()),
day: day,
})
.parse_next(input)
}
fn day(input: &mut &str) -> ModalResult<Day> {
s(alpha1)
.verify_map(|s: &str| {
Some(match s {
"monday" | "mon" | "mon." => Day::Monday,
"tuesday" | "tue" | "tue." | "tues" => Day::Tuesday,
"wednesday" | "wed" | "wed." | "wednes" => Day::Wednesday,
"thursday" | "thu" | "thu." | "thur" | "thurs" => Day::Thursday,
"friday" | "fri" | "fri." => Day::Friday,
"saturday" | "sat" | "sat." => Day::Saturday,
"sunday" | "sun" | "sun." => Day::Sunday,
_ => return None,
})
})
.parse_next(input)
}
#[cfg(test)]
mod tests {
use super::{parse, Day, Weekday};
#[test]
fn this_monday() {
for mut s in [
"monday",
"mon",
"mon.",
"this monday",
"this mon",
"this mon.",
"this monday",
"this - monday",
"0 monday",
] {
assert_eq!(
parse(&mut s).unwrap(),
Weekday {
offset: 0,
day: Day::Monday,
}
);
}
}
#[test]
fn next_tuesday() {
for s in ["tuesday", "tue", "tue.", "tues"] {
let s = format!("next {s}");
assert_eq!(
parse(&mut s.as_ref()).unwrap(),
Weekday {
offset: 1,
day: Day::Tuesday,
}
);
}
}
#[test]
fn last_wednesday() {
for s in ["wednesday", "wed", "wed.", "wednes"] {
let s = format!("last {s}");
assert_eq!(
parse(&mut s.as_ref()).unwrap(),
Weekday {
offset: -1,
day: Day::Wednesday,
}
);
}
}
}
+373 -178
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-120
View File
@@ -1,120 +0,0 @@
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";
}
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)?;
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,
};
for fmt in [
time_only_formats::HH_MM,
time_only_formats::HH_MM_SS,
time_only_formats::TWELVEHOUR,
] {
if let Ok(parsed) = NaiveTime::parse_from_str(captures["time"].trim(), fmt) {
let parsed_dt = date.date_naive().and_time(parsed);
let offset = match parsed_offset {
Some(offset) => offset,
None => *date.offset(),
};
return offset.from_local_datetime(&parsed_dt).single();
}
}
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_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)
}
}
-111
View File
@@ -1,111 +0,0 @@
// 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());
}
}
-99
View File
@@ -1,99 +0,0 @@
// 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());
}
}
}