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
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 52dca03c56 | |||
| d4384ceec9 | |||
| 46cc4147c7 | |||
| 93e1c9bfe7 | |||
| e7a7a0b07f | |||
| d4353d0888 | |||
| 8aee979de5 | |||
| f1fada62a6 | |||
| ca6a39c0a7 | |||
| db18db4e1d | |||
| c337aba9cb | |||
| 63cfc01e80 | |||
| 1daaeb42a2 | |||
| 3fcbac6fae | |||
| 65cd15dba9 | |||
| 65c88f3586 | |||
| 2c55db21fa | |||
| badc887606 | |||
| f8adcb6c88 | |||
| d0dceb6eaf | |||
| 45b9d9f09a | |||
| 0965130c1b | |||
| 51ddcb793f | |||
| 7985aa04ba | |||
| 5c0c9c4405 | |||
| 8dd8051eb7 | |||
| 073b9f7b70 | |||
| 0318dabe3a | |||
| 57fe123e21 | |||
| 2fe83cabf1 | |||
| 94d4112707 | |||
| eda2422bb3 | |||
| c948274c42 | |||
| b209341259 | |||
| 9cd22afa29 | |||
| a7061bce12 | |||
| ea49dc94f0 |
Generated
+3
-10
@@ -118,20 +118,13 @@ 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"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -151,7 +144,7 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "parse_datetime"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"nom",
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "parse_datetime"
|
||||
description = "parsing human-readable time strings and converting them to a DateTime"
|
||||
version = "0.7.0"
|
||||
version = "0.8.0"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/uutils/parse_datetime"
|
||||
@@ -10,4 +10,4 @@ readme = "README.md"
|
||||
[dependencies]
|
||||
regex = "1.10.4"
|
||||
chrono = { version="0.4.38", default-features=false, features=["std", "alloc", "clock"] }
|
||||
nom = "7.1.3"
|
||||
nom = "8.0.0"
|
||||
|
||||
@@ -18,9 +18,8 @@ A Rust crate for parsing human-readable relative time strings and human-readable
|
||||
|
||||
Add this to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
parse_datetime = "0.6.0"
|
||||
```
|
||||
cargo add parse_datetime
|
||||
```
|
||||
|
||||
Then, import the crate and use the `parse_datetime_at_date` function:
|
||||
|
||||
Generated
+17
-70
@@ -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]]
|
||||
@@ -84,21 +86,9 @@ 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.61"
|
||||
@@ -124,9 +114,9 @@ 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",
|
||||
]
|
||||
@@ -148,9 +138,9 @@ checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.4.8"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b9569d2f74e257076d8c6bfa73fb505b46b851e51ddaecc825944aa3bed17fa"
|
||||
checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"cc",
|
||||
@@ -168,20 +158,13 @@ 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"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -201,19 +184,13 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "parse_datetime"
|
||||
version = "0.6.0"
|
||||
version = "0.7.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"
|
||||
@@ -232,36 +209,6 @@ 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.11.1"
|
||||
@@ -291,6 +238,12 @@ version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[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"
|
||||
@@ -308,12 +261,6 @@ 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.93"
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
+396
-68
File diff suppressed because it is too large
Load Diff
+27
-17
@@ -20,6 +20,8 @@ const DAYS_PER_MONTH: [u32; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 3
|
||||
/// * `date` - A `Date` instance representing the base date for the calculation
|
||||
/// * `s` - A string slice representing the relative time.
|
||||
///
|
||||
/// If `s` is empty, the `date` is returned as-is.
|
||||
///
|
||||
/// # Supported formats
|
||||
///
|
||||
/// The function supports the following formats for relative time:
|
||||
@@ -51,6 +53,10 @@ pub fn parse_relative_time_at_date<T: TimeZone>(
|
||||
mut datetime: DateTime<T>,
|
||||
s: &str,
|
||||
) -> Result<DateTime<T>, ParseDateTimeError> {
|
||||
let s = s.trim();
|
||||
if s.is_empty() {
|
||||
return Ok(datetime);
|
||||
}
|
||||
let time_pattern: Regex = Regex::new(
|
||||
r"(?x)
|
||||
(?:(?P<value>[-+]?\d*)\s*)?
|
||||
@@ -278,6 +284,12 @@ mod tests {
|
||||
Ok(parsed - now)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_string() {
|
||||
let now = Utc::now();
|
||||
assert_eq!(parse_relative_time_at_date(now, "").unwrap(), now);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_years() {
|
||||
let now = Utc::now();
|
||||
@@ -285,10 +297,7 @@ mod tests {
|
||||
parse_relative_time_at_date(now, "1 year").unwrap(),
|
||||
now.checked_add_months(Months::new(12)).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "this year").unwrap(),
|
||||
now.checked_add_months(Months::new(0)).unwrap()
|
||||
);
|
||||
assert_eq!(parse_relative_time_at_date(now, "this year").unwrap(), now);
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "-2 years").unwrap(),
|
||||
now.checked_sub_months(Months::new(24)).unwrap()
|
||||
@@ -319,25 +328,24 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_months() {
|
||||
use crate::parse_relative_time::add_months;
|
||||
|
||||
let now = Utc::now();
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "1 month").unwrap(),
|
||||
now.checked_add_months(Months::new(1)).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "this month").unwrap(),
|
||||
now.checked_add_months(Months::new(0)).unwrap()
|
||||
add_months(now, 1, false).unwrap(),
|
||||
);
|
||||
assert_eq!(parse_relative_time_at_date(now, "this month").unwrap(), now);
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "1 month and 2 weeks").unwrap(),
|
||||
now.checked_add_months(Months::new(1))
|
||||
add_months(now, 1, false)
|
||||
.unwrap()
|
||||
.checked_add_days(Days::new(14))
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "1 month and 2 weeks ago").unwrap(),
|
||||
now.checked_sub_months(Months::new(1))
|
||||
add_months(now, 1, true)
|
||||
.unwrap()
|
||||
.checked_sub_days(Days::new(14))
|
||||
.unwrap()
|
||||
@@ -348,7 +356,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "month").unwrap(),
|
||||
now.checked_add_months(Months::new(1)).unwrap()
|
||||
add_months(now, 1, false).unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -562,6 +570,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_duration_parsing() {
|
||||
use crate::parse_relative_time::add_months;
|
||||
|
||||
let now = Utc::now();
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "1 year").unwrap(),
|
||||
@@ -582,25 +592,25 @@ mod tests {
|
||||
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "1 month").unwrap(),
|
||||
now.checked_add_months(Months::new(1)).unwrap()
|
||||
add_months(now, 1, false).unwrap(),
|
||||
);
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "1 month and 2 weeks").unwrap(),
|
||||
now.checked_add_months(Months::new(1))
|
||||
add_months(now, 1, false)
|
||||
.unwrap()
|
||||
.checked_add_days(Days::new(14))
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "1 month, 2 weeks").unwrap(),
|
||||
now.checked_add_months(Months::new(1))
|
||||
add_months(now, 1, false)
|
||||
.unwrap()
|
||||
.checked_add_days(Days::new(14))
|
||||
.unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "1 months 2 weeks").unwrap(),
|
||||
now.checked_add_months(Months::new(1))
|
||||
add_months(now, 1, false)
|
||||
.unwrap()
|
||||
.checked_add_days(Days::new(14))
|
||||
.unwrap()
|
||||
@@ -618,7 +628,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(
|
||||
parse_relative_time_at_date(now, "month").unwrap(),
|
||||
now.checked_add_months(Months::new(1)).unwrap()
|
||||
add_months(now, 1, false).unwrap(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -140,7 +140,7 @@ mod tests {
|
||||
let parsed_time = parse_time_only(get_test_date(), "21:04")
|
||||
.unwrap()
|
||||
.timestamp();
|
||||
assert_eq!(parsed_time, 1709499840)
|
||||
assert_eq!(parsed_time, 1709499840);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -187,7 +187,7 @@ mod tests {
|
||||
let parsed_time = parse_time_only(get_test_date(), "21:04:30")
|
||||
.unwrap()
|
||||
.timestamp();
|
||||
assert_eq!(parsed_time, 1709499870)
|
||||
assert_eq!(parsed_time, 1709499870);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -196,7 +196,7 @@ mod tests {
|
||||
let parsed_time = parse_time_only(get_test_date(), "21:04:30 +0530")
|
||||
.unwrap()
|
||||
.timestamp();
|
||||
assert_eq!(parsed_time, 1709480070)
|
||||
assert_eq!(parsed_time, 1709480070);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -205,6 +205,6 @@ mod tests {
|
||||
let parsed_time = parse_time_only(get_test_date(), "9:04:00 PM")
|
||||
.unwrap()
|
||||
.timestamp();
|
||||
assert_eq!(parsed_time, 1709499840)
|
||||
assert_eq!(parsed_time, 1709499840);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,7 @@ 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};
|
||||
use nom::{self, IResult, Parser};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ParseTimestampError {
|
||||
@@ -55,7 +54,7 @@ pub(crate) fn parse_timestamp(s: &str) -> Result<i64, ParseTimestampError> {
|
||||
|
||||
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(
|
||||
@@ -67,8 +66,9 @@ pub(crate) fn parse_timestamp(s: &str) -> Result<i64, ParseTimestampError> {
|
||||
|_, c| c,
|
||||
),
|
||||
digit1,
|
||||
)),
|
||||
))(s);
|
||||
),
|
||||
))
|
||||
.parse(s);
|
||||
|
||||
let (_, (sign, number_str)) = res?;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ use chrono::Weekday;
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag;
|
||||
use nom::combinator::value;
|
||||
use nom::{self, IResult};
|
||||
use nom::{self, IResult, Parser};
|
||||
|
||||
// Helper macro to simplify tag matching
|
||||
macro_rules! tag_match {
|
||||
@@ -25,7 +25,8 @@ pub(crate) fn parse_weekday(s: &str) -> Option<Weekday> {
|
||||
tag_match!(Weekday::Fri, "friday", "fri"),
|
||||
tag_match!(Weekday::Sat, "saturday", "sat"),
|
||||
tag_match!(Weekday::Sun, "sunday", "sun"),
|
||||
)))(s);
|
||||
)))
|
||||
.parse(s);
|
||||
|
||||
match parse_result {
|
||||
Ok((_, weekday)) => Some(weekday),
|
||||
@@ -63,9 +64,9 @@ mod tests {
|
||||
|
||||
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));
|
||||
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) = (
|
||||
|
||||
Reference in New Issue
Block a user