chrono
chrono copied to clipboard
Support parsing dates with missing fields
This example is documented as failing when parsing a NaiveDate:
assert!(parse_from_str("2015/9", "%Y/%m").is_err());
However, it would be more useful if unspecified fields defaulted to the lowest valid value. This is how the python date/time parsing works.
Alternatively, the API could provide a mechanism to supply "missing fields" separately from the string being parsed. It would be sufficient for this to work only for "prefixes", eg. "%Y", "%Y-%m", "%Y-%m-%d", and similarly for times.
I think that I prefer the idea of requiring missing fields to be supplied in some way to get around accidentally typoing the format string. We could make it a bit easier if it's expected by supplying a "default" default-supplier.
Have you seen an API that looks good for a supplier? The first thing that comes to mind is some sort of builder like, for your example:
// okay, ends up on the fifth:
Date::parse_defaults().day(5).parse_from_str("2015/9", "%Y/%m");
// error, day is what's missing:
Date::parse_defaults().month(1).parse_from_str("2015/9", "%Y/%m");
// okay, same result as the first example:
Date::parse_defaults().month(1).day(5).parse_from_str("2015/9", "%Y/%m");
// okay, uses first day of month:
Date::parse_defaults().first().parse_from_str("2015/9", "%Y/%m");
Is this the kind of thing you're imagining? Have you seen something better?
One possibility that comes to mind would be to add a new "DateTimeItems" type which just stores the parsed items but doesn't attempt to convert to a valid date (yet). Usage would look like:
let result: ParseResult<Date> = DateTimeItems::parse_from_str("2015/9", "%Y/%m").with_day(1).into();
Hmm actually yeah that would result in probably a much nicer API all around if we stuff DT Items in the Err variant (or something), then we don't need any new functions and can provide better error messages, and I think that the current code would support that without the kinds of crazy refactor I was scared of for my idea.
That would mean maybe some sort of new trait on ParseResults allowing just something like parse_from_str("..", "%Y/%m").with_day(1).
Hey, @quodlibetor. I see there hasn't been much progress on this issue since it was created. Is there any way I can help? This is a feature I need in a personal project and would be willing to help implement it :smiley:
@bernardobelchior PRs around this would be very welcome!
If you would like to take a look at the parsing code and come up with a bit of a proposal I could definitely guide you. You can feel free to ping me on gitter if you want to talk about it. My overall feeling about this is that we should implement a new trait for better dt parsing that we can incorporate in the 0.4.x series and replace the existing methods with in 0.5.x.
Hi. Is there any way to parse partial dates in the current version? Or maybe there is external crate for this? I need to parse dates like "1956-01" which are in the csv files. The problem is that different csv uses different format for datetime. That's why I would like to pass format string to the parsing function. Any tips are appreciated :-)
I have a workaround way to handle it.
use chrono::format::{parse, Parsed, StrftimeItems};
let datetime = "2015/9";
let fmt = "%Y/%m";
let mut parsed = Parsed::new();
parse(&mut parsed, datetime, StrftimeItems::new(fmt)).unwrap();
// set default values
parsed.year = parsed.year.or(Some(0));
parsed.month = parsed.month.or(Some(1));
parsed.day = parsed.day.or(Some(1));
if parsed.hour_div_12.is_none() {
parsed.set_hour(0).unwrap();
}
parsed.minute = parsed.minute.or(Some(0));
parsed.second = parsed.second.or(Some(0));
parsed.nanosecond = parsed.nanosecond.or(Some(0));
parsed.offset = parsed.offset.or(Some(0));
let datetime = parsed.to_datetime().unwrap()
println!("{datetime}"); // 2015-09-01 00:00:00 +00:00