Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean slate with Winnow 2 #86

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open

Conversation

dhilst
Copy link

@dhilst dhilst commented Aug 29, 2024

Continuing the rewrite started by @tertsdiepraam #61

  • The functions in lib.rs keep the same signature
  • I kept the tests in lib.rs too all they are passing
  • 90% of the parsing was written by @tertsdiepraam (check Clean slate with Winnow #61)
  • Added timestamp with @\d+ format
  • Added timezone abbreviation names
  • Added 8 digits dates MMDDhhmm
  • Using winnow

@dhilst
Copy link
Author

dhilst commented Aug 29, 2024

@tertsdiepraam I squashed your commits into a single commit, I hope you don't mind

@tertsdiepraam
Copy link
Member

Looks cool! A few initial comments to send you in the right direction. One of the reasons for this rewrite is that chrono wasn't cutting it for adding all the items together. Instead we should add all the items together ourselves to really match GNU. It'll require a lot of experimentation, but it'll make the compatibility much better. I think most of the corner cases were around the ends of months. I believe GNU had some overflow behaviour there that chrono didn't. So I recommend first creating a custom datetime struct to manipulate and then mapping that to chrono.

Squashing the commit is absolutely fine by the way. Thanks for continuing this!

@dhilst dhilst force-pushed the clean-slate-2 branch 16 times, most recently from 5516eed to 9388e45 Compare August 30, 2024 20:52
@dhilst dhilst force-pushed the clean-slate-2 branch 2 times, most recently from 7592100 to 44a8141 Compare September 2, 2024 22:53
@tertsdiepraam
Copy link
Member

Hi! I was looking at this again and I found an issue with how you're currently using chrono. Here's my theory:

  1. It's currently 2024-09-11 and September is a month with 30 days.
  2. I give as input: 2024-01-31
  3. While setting the Date item, you first change the day, then the month and then the year.
  4. At each of those, the validity is checked.
  5. That means that you adjust the date first to 2024-09-31, then 2024-01-31.
  6. However, 2024-09-31 is an invalid date and chrono will therefore yield and error even though I have entered a valid date.

We need to find a way to construct the times such that this never happens. Just changing the order won't cut it because that can still lead to invalid states. chrono might be more of a hindrance than a help here, unfortunately.

@dhilst dhilst force-pushed the clean-slate-2 branch 4 times, most recently from e858dfd to 417fde9 Compare September 14, 2024 00:01
@dhilst
Copy link
Author

dhilst commented Sep 14, 2024

Hi! I was looking at this again and I found an issue with how you're currently using chrono. Here's my theory:

1. It's currently 2024-09-11 and September is a month with 30 days.

2. I give as input: `2024-01-31`

3. While setting the `Date` item, you first change the day, then the month and then the year.

4. At each of those, the validity is checked.

5. That means that you adjust the date first to `2024-09-31`, then `2024-01-31`.

6. However, `2024-09-31` is an invalid date and `chrono` will therefore yield and error even though I have entered a valid date.

We need to find a way to construct the times such that this never happens. Just changing the order won't cut it because that can still lead to invalid states. chrono might be more of a hindrance than a help here, unfortunately.

Hi Terts,

I introduced a function to create dates from naive dates instead of using with_ method chains.

About the month behavior, if I understood correctly GNU gets the number of the days in the current month and adds it to the date, I implemented this behavior added your test and one more.

@dhilst
Copy link
Author

dhilst commented Sep 14, 2024

@tertsdiepraam I was looking into the fuzzy testing. I added the code so it generates fuzzy dates with some sanity and caught some problems, I will look into them next.

Comment on lines 81 to 97
// Testing GNU compatibility by calling date and
// comparing the inputs

// let fmt = "%Y-%m-%d %H:%M:%S";
// let mut output: process::Output = std::process::Command::new("date")
// .arg("-d")
// .arg(s)
// .arg(format!("+{fmt}"))
// .output()
// .expect("date command failed");
// io::stdout().write_all(&output.stdout).unwrap();
// io::stdout().write_all(&output.stderr).unwrap();
// output.stdout.pop(); // remove trailing \n
// assert_eq!(
// String::from_utf8(output.stdout).unwrap(),
// d.format(fmt).to_string()
// );
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was testing something like this to determine its compatibility with GNU. The test run GNU date in and compare the outputs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could definitely do that with fuzzing! We should still rely on regular tests as well though.

@dhilst dhilst force-pushed the clean-slate-2 branch 5 times, most recently from 2389d91 to 025808c Compare September 14, 2024 20:59
src/lib.rs Outdated
Comment on lines 478 to 491
#[test]
fn chrono_date() {
const FMT: &str = "%Y-%m-%d %H:%M:%S";
let input = "262144-03-10 00:00:00";

// chrono rejects this specific date
assert!(NaiveDate::from_ymd_opt(262144, 3, 10).is_none());
assert!(chrono::DateTime::parse_from_str(input, FMT).is_err());
// the parsing works, but hydration fails
assert!(items::parse(&mut input.to_string().as_str()).is_ok());
assert!(parse_datetime(input).is_err());
// GNU date works
assert_eq!(make_gnu_date(input, FMT), input);
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tertsdiepraam I found a case where GNU accepts the date, we can parse it and chrono rejects it, more precisely chrono::NaiveDate::from_ymd_opt returns None for this date. I don't know what direction to take from there, chrono keeps getting in the way 😅 ideas? Maybe having a gnu-compatible datetime layer, but that will be a lot of work

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another problem is with formatting too. chrono puts a + in front of the year if the year is >9999. This breaks some tests:

image
image

@dhilst dhilst force-pushed the clean-slate-2 branch 4 times, most recently from 539a63f to 307c159 Compare September 15, 2024 00:56
@sylvestre
Copy link
Sponsor Contributor

sorry but some tests are failing:

failures:
    items::date::tests::test_year
    items::date::tests::with_year
    items::tests::date_and_time
    tests::offsets::invalid_offset_format
    tests::test_relative::chrono_date
    tests::test_relative::gnu_compat
    tests::test_relative::test_month

and needs some rebasing

@dhilst
Copy link
Author

dhilst commented Sep 17, 2024

sorry but some tests are failing:

failures:
    items::date::tests::test_year
    items::date::tests::with_year
    items::tests::date_and_time
    tests::offsets::invalid_offset_format
    tests::test_relative::chrono_date
    tests::test_relative::gnu_compat
    tests::test_relative::test_month

and needs some rebasing

I will rebase it

But right now I have a problem with Chrono, I'm looking into alternatives like https://time-rs.github.io/book/how-to/create-dates.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants